如何生成两个不同的随机数矩阵,使得它们所有元素的和都相等?

huangapple go评论109阅读模式
英文:

How can I generate two diferrent matrices of random numbers, under the condition that the sum of all their elements is for both the same?

问题

以下是代码部分的中文翻译:

// 我在C++中创建了两个不同的随机生成数字矩阵:

a = new int* [IT]();
    for (int j = 0; j < IT; j++) {
        a[j] = new int[P];
        for (int p = 0; p < P; p++) {
            a[j]

= RL.randint(0,100); // 我在另一个cpp文件中创建了randint函数 } } b = new int* [OT](); for (int m = 0; m < OT; m++) { b[m] = new int[P]; for (int p = 0; p < P; p++) { b[m]

= RL.randint(0, 100); } }

希望这有所帮助。如果您有其他问题,请随时提出。

英文:

I have created two different matrices of randomly generated numbers in C++:

a = new int* [IT]();
    for (int j = 0; j < IT; j++) {
        a[j] = new int[P];
        for (int p = 0; p < P; p++) {
            a[j]

= RL.randint(0,100); // I have created the randint function in another cpp file } } b = new int* [OT](); for (int m = 0; m < OT; m++) { b[m] = new int[P]; for (int p = 0; p < P; p++) { b[m]

= RL.randint(0, 100); } }

Now i want to implement somehow the condition that:
∑(j,p)〖a(j,p)〗= ∑(m,p)〖b(m,p)〗

I didn't find anything that could help me in Google, only some examples of generating numbers under the condition that their sum meats a certain target (eg. sumofrandnumbs = 6). In my case I don't have a specific number that i want to meet, only the criterion that the two sums must be the same. I am thinking maybe it's easier to generate the numbers under this criterion in excel and then fetch them into my cpp file and put them into the a and b matrices. I don't know how to do that either but i have found some information online. Your help would mean a lot.Thank you very much.

答案1

得分: 1

计算速率 K = Sum_of_a/Sum_of_b

然后,如果 K<=1.0,将此 K 乘以 b,否则将 1/K 乘以 a(此选择是为了保持所有元素值<= 100)。

但是,由于元素类型是整数,稍后需要进行一些调整。
(例如,重新检查结果总和并在随机位置添加不足之处。)

英文:

Calculate the rate K = Sum_of_a/Sum_of_b.

Then, if K&lt;=1.0 multiply this K to b else multiply 1/K to a (This selection is to keep all element values <= 100).

However, since the element type is int, some adjustments will be necessary later.
(Like re-checking the result sum and adding the shortfall at random places.)

答案2

得分: 0

以下是翻译好的部分:

What I would do is compute the delta between the 2 sums and then change delta values in the second array to get the same sums.
我要做的是计算两个总和之间的差值,然后更改第二个数组中的差值,以获得相同的总和。

Within OPL CPLEX I would write this :
在 OPL CPLEX 中,我会这样写:

int n=5;
int n=5;

range r=1..n;
范围 r=1..n;

int ar1[i in r][j in r]=rand(101);
int ar1[i in r][j in r]=rand(101);

int ar2[i in r][j in r]=rand(101);
int ar2[i in r][j in r]=rand(101);

int sum1=sum(i,j in r) ar1[i][j];
int sum1=sum(i,j in r) ar1[i][j];

int sum2=sum(i,j in r) ar2[i][j];
int sum2=sum(i,j in r) ar2[i][j];

int delta=sum2-sum1;
int delta=sum2-sum1;

int absdelta=ftoi(abs(delta));
int absdelta=ftoi(abs(delta));

int inc=-delta div absdelta;
int inc=-delta div absdelta;

range rabsdelta=1..absdelta;
范围 rabsdelta=1..absdelta;

execute
{
writeln("sum1=",sum1);
writeln("sum2=",sum2);
}
execute
{
writeln("sum1=",sum1);
writeln("sum2=",sum2);
}

execute
{
for(var i in rabsdelta)
{
var x=1+Opl.rand(n);
var y=1+Opl.rand(n);
ar2[x][y]=ar2[x][y]+inc;
}
}
execute
{
for(var i in rabsdelta)
{
var x=1+Opl.rand(n);
var y=1+Opl.rand(n);
ar2[x][y]=ar2[x][y]+inc;
}
}

int sum1after=sum(i,j in r) ar1[i][j];
int sum1after=sum(i,j in r) ar1[i][j];

int sum2after=sum(i,j in r) ar2[i][j];
int sum2after=sum(i,j in r) ar2[i][j];

execute
{
writeln();
writeln("after move delta values");
writeln();
writeln("sum1=",sum1after);
writeln("sum2=",sum2after);
}
execute
{
writeln();
writeln("after move delta values");
writeln();
writeln("sum1=",sum1after);
writeln("sum2=",sum2after);
}

which gives
这会得到以下结果:

sum1=1311
sum2=1559

after move delta values
在移动差值后

sum1=1311
sum2=1311
sum1=1311
sum2=1559

after move delta values
在移动差值后

sum1=1311
sum2=1311

英文:

What I would do is compute the delta between the 2 sums and then change delta values in the second array to get the same sums.

Within OPL CPLEX I would write this :

int n=5;
range r=1..n;

int ar1[i in r][j in r]=rand(101);
int ar2[i in r][j in r]=rand(101);

int sum1=sum(i,j in r) ar1[i][j];
int sum2=sum(i,j in r) ar2[i][j];

int delta=sum2-sum1;
int absdelta=ftoi(abs(delta));
int inc=-delta div absdelta;

range rabsdelta=1..absdelta;

execute
{
  writeln(&quot;sum1=&quot;,sum1);
  writeln(&quot;sum2=&quot;,sum2);
}

execute
{
  for(var i in rabsdelta)
  {
    var x=1+Opl.rand(n);
    var y=1+Opl.rand(n);
    ar2[x][y]=ar2[x][y]+inc;
  }
}

int sum1after=sum(i,j in r) ar1[i][j];
int sum2after=sum(i,j in r) ar2[i][j];

execute
{
  writeln();
  writeln(&quot;after move delta values&quot;);
  writeln();
  writeln(&quot;sum1=&quot;,sum1after);
  writeln(&quot;sum2=&quot;,sum2after);
}

which gives

sum1=1311
sum2=1559

after move delta values

sum1=1311
sum2=1311

答案3

得分: 0

以下是您要翻译的内容:

How can I generate two different matrices of random numbers, [...]?

有很多开源的线性代数库,但我将在这里重新发明轮子,开始编写一个(不完整且几乎不起作用的)矩阵类。

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

template<typename T>
class Matrix
{
    std::vector<T> d_;
    int rows_, cols_;
public:
    Matrix(int r, int c)
        : d_(checked_size(r) * checked_size(c))
        , rows_(r), cols_(c)
    {}
    template<typename Gen>
    // 此构造函数使用传递的生成器来初始化矩阵值。
    Matrix(int r, int c, Gen&& gen) : Matrix(r, c)
    {
        std::generate(begin(), end(), gen);
    }

    // 其他访问器留给读者自己实现。
    auto rows() const noexcept { return rows_; }
    auto columns() const noexcept { return cols_; }
    auto begin() const noexcept { return d_.begin(); }
    auto begin() noexcept { return d_.begin(); }
    auto end() const noexcept { return d_.end(); }
    auto end() noexcept { return d_.end(); }
private:
    auto checked_size(int s)
    {
        if (s <= 0) throw std::domain_error{"必须大于零"};
        return static_cast<std::size_t>(s);
    }
};

template<typename T>
auto operator<<(std::ostream& os, Matrix<T> const& m) -> std::ostream&
{
    auto width{ static_cast<int>(os.width()) };
    for (auto i{ std::begin(m) }; i != std::end(m); )
    {
        for (auto j{ i + m.columns() }; i != j; ++i)
            os << std::setw(width) << *i;
        os << '\n';
    }
    return os;
}

int main()
{
    // 初始化基于Mersenne Twister算法的随机数引擎。
    // 它将被分布用于生成伪随机数。
    auto eng{ []{
        std::random_device rd;
        std::seed_seq ss{ rd(), rd(), rd() };
        return std::mt19937{ ss };
    }() };
    
    auto rnd_int{ [&eng]{ 
        static std::uniform_int_distribution dist(0, 100);
        return dist(eng); 
    }};
    
    Matrix<int> a(10, 10, rnd_int);
    std::cout << std::setw(4) << a
              << "Sum: " << std::accumulate(a.begin(), a.end(), 0ll) << "\n\n";
}

现在我们已经生成了一个矩阵,我们可以进行转换,使其元素的总和保持不变。在标准库中,有一个叫做std::shuffle的算法,它可以重新排列给定范围[first, last)中的元素,以使这些元素的每个可能排列都有相等的出现概率。

我将修改其中一个可能的实现,以便它不仅仅交换两个元素,而是应用更通用的转换。

template<class RandomIt, class URBG, class S>
void shuffle(RandomIt first, RandomIt last, URBG&& g, S&& scramble)
{
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
    typedef std::uniform_int_distribution<diff_t> distr_t;
    typedef typename distr_t::param_type param_t;
 
    distr_t D;
    for (diff_t i = last - first - 1; i > 0; --i)
    {
        scramble(first[i], first[D(g, param_t(0, i)]);      // <--
    }
}

思想是,我们可以取矩阵中的任意一对元素,改变它们的值,只要它们的总和保持不变,全局总和也不会改变。

auto noiser{ [&eng](int& a, int& b) {
    if (&a == &b)  // <- 这看起来有点丑,但我们需要避免这种情况。
        return;
    auto const sum{ a + b };
    /*
        0---A-------B-------100             0--------A--------B-100
        <-----A'-------->                          <----A'------> 
    */
    std::uniform_int_distribution d(std::max(0, sum - 100), std::min(100, sum));
    a = d(eng);
    b = sum - a;
}};

Live: https://godbolt.org/z/a1f5s9v4W

1) https://godbolt.org/z/Ga9841v9a
2) https://en.cppreference.com/w/cpp/algorithm/random_shuffle
3) Version 3 (shuffle) at https://en.cppreference.com/w/cpp/algorithm/random_shuffle#Possible_implementation

英文:

> How can I generate two diferrent matrices of random numbers, [...]?

There are plenty of open source linear algebra libraries, but I'll just reinvent the wheel here and start writing<sup>1</sup> a (incomplete and barely functioning) matrix class.

#include &lt;algorithm&gt;
#include &lt;iomanip&gt;
#include &lt;iostream&gt;
#include &lt;random&gt;
#include &lt;vector&gt;

template&lt; typename T &gt;
class Matrix
{
    std::vector&lt;T&gt; d_;
    int rows_, cols_;
public:
    Matrix(int r, int c)
        : d_(checked_size(r) * checked_size(c))
        , rows_(r), cols_(c)
    {}
    template&lt; typename Gen &gt;
    // This constructor uses the passed generator to initialize the matrix values.
    Matrix(int r, int c, Gen&amp;&amp; gen) : Matrix(r, c)
    {
        std::generate(begin(), end(), gen);
    }

    // Other accessors are left to the reader.
    auto rows()    const noexcept { return rows_; }
    auto columns() const noexcept { return cols_; }
    auto begin() const noexcept { return d_.begin(); }
    auto begin()       noexcept { return d_.begin(); }
    auto end()   const noexcept { return d_.end(); }
    auto end()         noexcept { return d_.end(); }
private:
    auto checked_size(int s)
    {
        if ( s &lt;= 0 ) throw std::domain_error{&quot;Must be greater than zero&quot;};
        return static_cast&lt;std::size_t&gt;(s);
    }
};

template&lt; typename T &gt;
auto operator&lt;&lt; (std::ostream&amp; os, Matrix&lt;T&gt; const&amp; m) -&gt; std::ostream&amp;
{
    auto width{ static_cast&lt;int&gt;(os.width()) };
    for( auto i{ std::begin(m) }; i != std::end(m); )
    {
        for( auto j{ i + m.columns() }; i != j; ++i )
            os &lt;&lt; std::setw(width) &lt;&lt; *i;
        os &lt;&lt; &#39;\n&#39;;
    }
    return os;
}

int main()
{
    // Initialize a random number engine based on Mersenne Twister algorithm.
    // It will be used by the distribution to generate pseudo-random numbers.
    auto eng{ []{
        std::random_device rd;
        std::seed_seq ss{ rd(), rd(), rd() };
        return std::mt19937{ ss };
    }() };
    
    auto rnd_int{ [&amp;eng]{ 
        static std::uniform_int_distribution dist(0, 100);
        return dist(eng); 
    }};
    
    Matrix&lt;int&gt; a(10, 10, rnd_int);
    std::cout &lt;&lt; std::setw(4) &lt;&lt; a
              &lt;&lt; &quot;Sum: &quot; &lt;&lt; std::accumulate(a.begin(), a.end(), 0ll) &lt;&lt; &quot;\n\n&quot;;
}

Now that we have generated one matrix, we can transform it such that the sum of its elements remains constant. In the Standard Library, there's an algorithm<sup>2</sup> called std::shuffle which

> Reorders the elements in the given range [first, last) such that each possible permutation of those elements has equal probability of appearance.

I'm going to modify one of its possible implementations<sup>3</sup>, so that instead of just swapping two elements it will apply a more generic transformation.

template&lt;class RandomIt, class URBG, class S&gt;
void shuffle(RandomIt first, RandomIt last, URBG&amp;&amp; g, S&amp;&amp; scramble)
{
    typedef typename std::iterator_traits&lt;RandomIt&gt;::difference_type diff_t;
    typedef std::uniform_int_distribution&lt;diff_t&gt; distr_t;
    typedef typename distr_t::param_type param_t;
 
    distr_t D;
    for (diff_t i = last - first - 1; i &gt; 0; --i)
    {
        scramble(first[i], first[D(g, param_t(0, i))]);      // &lt;--
    }
}

The idea is that we can take any pair of elements in the matrix, change their values and, as long as their sum remains the same, the global sum won't change either.

auto noiser{ [&amp;eng](int&amp; a, int&amp; b) {
    if ( &amp;a == &amp;b )  // &lt;- It&#39;s ugly, but we need to avoid this case.
        return;
    auto const sum{ a + b };
    /*
        0---A-------B-------100             0--------A--------B-100
        &lt;-----A&#39;--------&gt;                          &lt;----A&#39;------&gt; 
    */
    std::uniform_int_distribution d(std::max(0, sum - 100), std::min(100, sum));
    a = d(eng);
    b = sum - a;
}};

Live: https://godbolt.org/z/a1f5s9v4W


<sup>1) https://godbolt.org/z/Ga9841v9a </sup>
<sup>2) https://en.cppreference.com/w/cpp/algorithm/random_shuffle </sup>
<sup>3) Version 3 (shuffle) at https://en.cppreference.com/w/cpp/algorithm/random_shuffle#Possible_implementation </sup>

答案4

得分: -1

以下是翻译好的内容:

除非你想要欺骗输出,否则你不能在一次迭代步骤中实现它。
你需要为第一个矩阵获取随机数矩阵,并将和值存储在某个变量中,然后需要一遍又一遍地生成第二个矩阵,直到它的和等于第一个矩阵的和,代码看起来像这样:
int suma = 0;
a = new int*[IT]();
for (int j = 0; j &lt; IT; j++) {
a[j] = new int[P];
for (int p = 0; p &lt; P; p++) {
a[j]

= RL.randint(0, 100); suma += a[j]

; } } b = new int*[OT](); while (true) { int sumb = 0; for (int m = 0; m &lt; OT; m++) { b[m] = new int[P]; for (int p = 0; p &lt; P; p++) { b[m]

= RL.randint(0, 100); sumb += b[m]

; } } if (suma == sumb) { break; } }

但是,如果你追求速度,这种方法并不推荐。如果P很大,这将至少迭代几百万次。

时间复杂度将是O((允许的随机数长度)(OT*P)),所以对于3x3来说是O(1009),这是最坏的情况。

但是,我们可以通过一种简单的技巧来欺骗,即在第二个数组中生成除最后一个数之外的所有随机数,然后通过以下方式找到最后一个数:

b[OT-1][P-1] = suma - sumb - b[OT-1][P-1];

代码看起来像这样:

int suma = 0;
a = new int*[IT]();
for (int j = 0; j &lt; IT; j++) {
a[j] = new int[P];
for (int p = 0; p &lt; P; p++) {
a[j]

= RL.randint(0, 100); suma += a[j]

; } } b = new int*[OT](); int sumb = 0; for (int m = 0; m &lt; OT; m++) { b[m] = new int[P]; for (int p = 0; p &lt; P; p++) { b[m]

= RL.randint(0, 100); sumb += b[m]

; } } b[OT-1][P-1] = suma - sumb - b[OT-1][P-1];

现在,无论概率如何,这将在单次迭代中产生一个有保证的输出。但是请调整一些随机数,以确保你始终得到修改后的值中的正数。如果这有所帮助,欢迎点赞。

英文:

you can not implement it in one single iteration step unless you want to cheat on the output.

you have to get a matrix of random number for the first number and store the sum value at some variable then you need repeatedly generate the second matrix again and again until its sum is equal to first one and the code looks something like this

<pre>

int suma=0
a = new int* [IT]();
for (int j = 0; j &amp;lt IT; j++) {
a[j] = new int[P];
for (int p = 0; p &amp;lt P; p++) {
a[j]

= RL.randint(0,100); suma+=a[j]

; } } b = new int* [OT](); while(true){ sumb=0 for (int m = 0; m &amp;lt OT; m++) { b[m] = new int[P]; for (int p = 0; p &amp;lt P; p++) { b[m]

= RL.randint(0, 100); sumb+=b[m]

; } } if(suma == sumb){ break; } }

</pre>

but this method is not recommend this at all if the speed is it you are looking.

this will iterate at least of few million times if p is large.

time complexity will be O((random Number Allowed Length)(OT*P))
so, O(100
9) for the 3x3. this worst case.

but we can cheat this by simple technique by generating all random numbers in the second array except the last number. and find the last number by
<pre>

b[OT-1][P-1]=suma-sumb-b[Ot-1][P-1];

</pre>
the code looks something like this;

<pre>

int suma=0
a = new int* [IT]();
for (int j = 0; j &amp;lt IT; j++) {
a[j] = new int[P];
for (int p = 0; p &amp;lt P; p++) {
a[j]

= RL.randint(0,100); suma+=a[j]

; } } b = new int* [OT](); int sumb=0 for (int m = 0; m &amp;lt OT; m++) { b[m] = new int[P]; for (int p = 0; p &amp;lt P; p++) { b[m]

= RL.randint(0, 100); sumb+=b[m]

; } } b[OT-1][P-1]=suma-sumb-b[Ot-1][P-1];

</pre>

now this will have a guaranteed output with single iteration regardless of the probability. but adjust some random numbers such that you always end up with positive number in the modified value.

if this helps, leaving a upvote is appreciated.

huangapple
  • 本文由 发表于 2023年3月1日 13:55:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600021.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定