随机生成数据

\(OI\)学习过程中,数据是必不可少的。不管是在\(OJ\)上提交狂\(Wa\)不止时,还是考场上怀疑自己的算法但出题人给的数据又能正确\(AC\)时,数据都显得尤为重要。所以我特地写一篇随机数据生成的博客来总结一下。

随机函数

首先我们需要认识一下\(C++\)自带的随机函数\(rand()\)。头文件\(algorithm\)自带\(srand\)\(rand\)两个函数。

使用\(rand()\)函数会随机返回一个范围在[0,RAND_MAX]之间的整数。RAND_MAX等于\(2147483647\)也就是\(int\)能保存的最大的正整数。你想要\(rand\)一个[0,n-1]范围的数你可以\(rand()\)%\(n\),如果你想要\(rand()\)出负数你可以写成\(rand()\)%(\(2\)*\(n\))-\(n\)。这样\(rand\)出的数都是在\([-n,n-1]\)中等概率取值的。如果你要随机实数就写成\((double)rand()/eps\)。令\(eps\)等于\(10\)的若干次方即可。\(srand()\)函数带的参数是随机种子,种子不一样随机出来的数也不一样。我一般习惯写成\(srand(time(0))\),那么就会以当前时间为种子。第一次随机取值会根据种子来决定,之后的随机取值会以上一次随机出的值为种子来随机。这就是随机函数的运行机制。另外,\(algorithm\)里的random_shuffle也是根据种子来随机的。

随机生成排列

for(int i=1;i<=n;i++)
    a[i]=i;
random_shuffle(a+1,a+n+1);
for(int i=1;i<=n;i++)
    printf("%d ",a[i]);

随机生成若干个区间

for(int i=1;i<=m;i++) {
    int l=rand()%n+1,r=rand()%n+1;
    if(l>r)swap(l,r);
    printf("%d %d\n",l,r);
}

随机生成树

下面的\(n\)全部代表点数,\(m\)全部代表边数。

for(int i=2;i<=n;i++) {
    int i_father=rand()%(i-1)+1;
    printf("%d %d\n",i_father,i);
}

生成链

for(int i=2;i<=n;i++)
    printf("%d %d\n",i-1,i);

生成菊花图

for(int i=2;i<=n;i++)
    printf("1 %d\n",i);

随机生成联通图

#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;

int n,m;
map<pair<int,int>,bool> g;

int main() {
    scanf("%d%d",&n,&m);
    printf("%d %d\n",n,m);
    for(int i=2;i<=n;i++) {
        int i_father=rand()%(i-1)+1;
        g[make_pair(i_father,i)]=1;
        g[make_pair(i,i_father)]=1;
        printf("%d %d\n",i_father,i);
    }
    for(int i=n;i<=m;i++) {
        int a=rand()%n+1,b=rand()%n+1;
        while(g[make_pair(a,b)])a=rand()%n+1,b=rand()%n+1;
        g[make_pair(a,b)]=1;g[make_pair(b,a)]=1;
    }
}

不要求联通就不要先建一棵树了。

猜你喜欢

转载自www.cnblogs.com/AKMer/p/9895156.html
今日推荐