在(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
",l,r);
}
随机生成树
下面的(n)全部代表点数,(m)全部代表边数。
for(int i=2;i<=n;i++) {
int i_father=rand()%(i-1)+1;
printf("%d %d
",i_father,i);
}
生成链
for(int i=2;i<=n;i++)
printf("%d %d
",i-1,i);
生成菊花图
for(int i=2;i<=n;i++)
printf("1 %d
",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,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
",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;
}
}
不要求联通就不要先建一棵树了。