c++ 我怎样才能生成两个不同的随机数矩阵,条件是它们所有元素的和都是相同的?

xesrikrc  于 2023-03-05  发布在  其他
关注(0)|答案(4)|浏览(162)

我用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][p] = 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][p] = RL.randint(0, 100); 
        }
    }

现在我想实现某种条件:∑(j,p)〖 a(j,p)〗 = ∑(m,p)〖 b(m,p)〗
我在谷歌上没有找到任何可以帮助我的东西,只有一些在总和满足一定目标的情况下生成数字的例子(例如,sumofrandnumbs = 6)。在我的情况下,我没有我想要满足的特定数字,只有两个和必须相同的标准。我在想也许它在excel中生成这个标准下的数字比较容易,然后把它们取到我的cpp文件中,并把它们放入a和b矩阵中。我也不知道怎么做,但我在网上找到了一些信息。你的帮助将意味着很多。非常感谢。

ycl3bljg

ycl3bljg1#

计算速率K = Sum_of_a/Sum_of_b
然后,如果K<=1.0,则将此K乘以b,否则将1/K乘以a(此选择是为了保持所有元素值〈= 100)。
但是,由于元素类型是int,所以稍后需要进行一些调整(比如重新检查结果总和,并在随机位置添加不足部分)。

niwlg2el

niwlg2el2#

我要做的是计算两个和之间的增量,然后更改第二个数组中的增量值以获得相同的和。
在OPL CPLEX中,我会这样写:

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("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;
  }
}

int sum1after=sum(i,j in r) ar1[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);
}

它给出了

sum1=1311
sum2=1559

after move delta values

sum1=1311
sum2=1311
qpgpyjmq

qpgpyjmq3#

我如何生成两个不同的随机数矩阵[...]?
有很多开源线性代数库,但我在这里只是重新发明轮子,开始写一个(不完整且几乎不能运行)矩阵类。

#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 >
    // This constructor uses the passed generator to initialize the matrix values.
    Matrix(int r, int c, Gen&& 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 <= 0 ) throw std::domain_error{"Must be greater than zero"};
        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()
{
    // 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{ [&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的算法2,它
对给定范围[first,last]中的元素重新排序,使这些元素的每个可能排列具有相等的出现概率。
我将修改它的一个可能的实现3,这样它将应用一个更通用的转换,而不是仅仅交换两个元素。

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 )  // <- It's ugly, but we need to avoid this case.
        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;
}};

实时:https://godbolt.org/z/a1f5s9v4W
1)https://godbolt.org/z/Ga9841v9a
2)https://en.cppreference.com/w/cpp/algorithm/random_shuffle
3)第3版(随机播放),网址为https://en.cppreference.com/w/cpp/algorithm/random_shuffle#Possible_implementation

nc1teljy

nc1teljy4#

你不能在一个迭代步骤中实现它,除非你想在输出上作弊。
你必须为第一个数得到一个随机数矩阵,并将和值存储在某个变量中,然后你需要一次又一次地重复生成第二个矩阵,直到它的和等于第一个,代码看起来像这样

int suma=0
    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][p] = RL.randint(0,100); 
            suma+=a[j][p];
        }
    }
    b = new int* [OT]();
    while(true){
        sumb=0
        for (int m = 0; m < OT; m++) {
            b[m] = new int[P];
            for (int p = 0; p < P; p++) {
                b[m][p] = RL.randint(0, 100); 
                sumb+=b[m][p];
            }
        }
        if(suma == sumb){
            break;
        }
    }

但这种方法是不建议这在所有如果速度是它你正在寻找。
如果p较大,则这将迭代至少几百万次。
时间复杂度将是O((随机数允许长度)(OT*P)),因此,对于3 × 3,该最坏情况是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 < IT; j++) {
        a[j] = new int[P];
        for (int p = 0; p < P; p++) {
            a[j][p] = RL.randint(0,100); 
            suma+=a[j][p];
        }
    }
    b = new int* [OT]();
    int sumb=0
    for (int m = 0; m < OT; m++) {
        b[m] = new int[P];
        for (int p = 0; p < P; p++) {
            b[m][p] = RL.randint(0, 100); 
            sumb+=b[m][p];
        }
    }
    b[OT-1][P-1]=suma-sumb-b[Ot-1][P-1];

现在这将有一个保证的输出与单迭代无关的概率.但调整一些随机数,使你总是结束了正数在修改值.
如果这有帮助的话,留下一张赞成票是很受欢迎的。

相关问题