Algorithm 将一个数拆分为随机的非零数

Algorithm 将一个数拆分为随机的非零数,algorithm,math,Algorithm,Math,我有几对数字,比如说 [X1,Y1], [X2,Y2] ..... [Xn,Yn] Y > X 我还有一个数字,比如Z。现在我想把Z分成随机值Nm,这样它总是满足以下条件: N1 + N2 + N3 ...... Nn = Z Nm > 0 Nm <= Ym - Xm N1+N2+N3。。。。。。Nn=Z 纳米>0 Nm如果序列y_1-x_1+…+y_m-x_my_m-x_m 前NNI的每个Ni i总计达上界,因为它是一个随机数在0和1之间的上界,最后一个值落在范

我有几对数字,比如说

[X1,Y1], [X2,Y2] ..... [Xn,Yn]    Y > X
我还有一个数字,比如Z。现在我想把Z分成随机值Nm,这样它总是满足以下条件:

N1 + N2 + N3 ...... Nn = Z
Nm > 0
Nm <=  Ym - Xm
N1+N2+N3。。。。。。Nn=Z
纳米>0
Nm
如果序列y_1-x_1+…+y_m-x_my_m-x_m

前NNI的每个Ni i总计达上界,因为它是一个随机数在0和1之间的上界,最后一个值落在范围内,因为如果没有,我们会循环并再次尝试。数字加起来是Z,因为NYM是Z的差和其余的级数的和。< /P> < P>你有M个区间[席,Yi ]。你需要在每个区间内有一个随机数,这样所有的数之和就是Z

这些数字的总和必须介于和(Xi)和和和(Yi)之间。因此,我们同时计算:

Zmin = 0;
Zmax = 0;
for (i = 0; i < m; i++) {
    Zmin += X[i];
    Zmax += Y[i];
    Z[i] = X[i];
}
这是PHP中的一个快速实现,看起来很有效

<?php
    $X = [ 1, 4, 11, 3, 5, 17, 22, 35, 120, 0 ];
    $Y = [ 8, 9, 33, 9, 9, 28, 24, 36, 215, 3 ];

    $m = count($X);

    $ZZ= 0;
    // Construct a Z that will work.
    for ($i = 0; $i < $m; $i++) {
        // $Y[$i] = rand($X[$i], $X[$i] + 20);
        $ZZ += rand($X[$i], $Y[$i]);
    }

    $Zmin = 0;
    $Zmax = 0;

    for ($i = 0; $i < $m; $i++) {
        $Zmin += $X[$i];
        $Zmax += $Y[$i];
    }

    $R = $ZZ - $Zmin;
    if (($R < 0) || ($R + $Zmin > $Zmax)) {
        die("Can't do.\n");
    }

    $D = $Zmax - $Zmin;

   for ($i = 0; $i < $m; $i++) {
        $A = max($R-$D, 0); // Cannot distribute less than this.
        $B = min($Y[$i]-$X[$i], $R); // Nor more than this.


        $Q = ($B - $A); // This is positive, or we would have failed earlier
        assert('$Q > 0');

        $Z[$i] = $X[$i] + rand($A, $B); // floor($A + ($B-$A)*rand());

        $R -= ($Z[$i] - $X[$i]);
        assert('$R >= 0');
        assert('$X[$i] <= $Z[$i]');
        assert('$Y[$i] >= $Z[$i]');
   }

X1
Y1
等从何而来?您可能想要
Xm@MarkDickinson:更正约束如果X1>Z怎么办?可能吗?
remainder = Z - Zmin;
if ((remainder < 0) || (remainder + Zmin > Zmax)) {
    // Can't do.
}

// There are several ways of equidistributing the remainder.
// This is not one of them, but it's simple.
// If Z is very near Zmax, performances will suffer.
while (remainder > 0) {
    // Choose 
    i = rand()*m;
    // Can we increase Z[i]?
    if (Z[i] < Y[i]) {
        Z[i]++;
        remainder--;
    }
}
// DONE!
D = Zmax - Zmin;

for (i = 0; i < m; i++) {

    V = MAX(remainder-D, 0);

    Q = (Y[i] - X[i]) - V; // This is positive, or we would have failed earlier

    Z[i] = Y[i]-X[i]-Q+rand()*(Q*remainder/(D+Q));

    remainder -= (Z[i] - X[i]);
}
<?php
    $X = [ 1, 4, 11, 3, 5, 17, 22, 35, 120, 0 ];
    $Y = [ 8, 9, 33, 9, 9, 28, 24, 36, 215, 3 ];

    $m = count($X);

    $ZZ= 0;
    // Construct a Z that will work.
    for ($i = 0; $i < $m; $i++) {
        // $Y[$i] = rand($X[$i], $X[$i] + 20);
        $ZZ += rand($X[$i], $Y[$i]);
    }

    $Zmin = 0;
    $Zmax = 0;

    for ($i = 0; $i < $m; $i++) {
        $Zmin += $X[$i];
        $Zmax += $Y[$i];
    }

    $R = $ZZ - $Zmin;
    if (($R < 0) || ($R + $Zmin > $Zmax)) {
        die("Can't do.\n");
    }

    $D = $Zmax - $Zmin;

   for ($i = 0; $i < $m; $i++) {
        $A = max($R-$D, 0); // Cannot distribute less than this.
        $B = min($Y[$i]-$X[$i], $R); // Nor more than this.


        $Q = ($B - $A); // This is positive, or we would have failed earlier
        assert('$Q > 0');

        $Z[$i] = $X[$i] + rand($A, $B); // floor($A + ($B-$A)*rand());

        $R -= ($Z[$i] - $X[$i]);
        assert('$R >= 0');
        assert('$X[$i] <= $Z[$i]');
        assert('$Y[$i] >= $Z[$i]');
   }