1. 随机生成整数序列
目标:随机生成 n≤105 个绝对值在 109 以内的整数。(可能包含负数)
技巧:
- 若要同时产生负数,则可以先产生一个 0~2n 之间的随机整数,再减去 n,就得到了 -n~n 之间的随机整数。
- 若要随机实数,则可以先产生一个较大的随机整数,再用它除以 10 的次幂。
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ srand(time(0)); int n=rand()%(int)1e5+1,m=1e9; for(int i=1;i<=n;i++){ int x=rand()%(2*m+1)-m; cout<<x<<" "; } return 0; }
也可以随机一个 1~2 之间的随机整数,若随机出来是 1,则输出 x,否则输出 -x。
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ srand(time(0)); int n=rand()%(int)1e5+1,m=1e9; for(int i=1;i<=n;i++){ int x=rand()%m,y=rand()%2+1; if(y==1) x=-x; cout<<x<<" "; } return 0; }
rand 函数也可以这么写:
以下代码中,函数 random(n) 返回 0~n-1 之间的随机整数,并综合考虑了操作系统和编译器环境的差异,对 int 范围内的 n 均能正常工作。
int random(int n){ return rand()*rand()%n; }
2. 随机生成区间列
目标:随机生成 m 个 [1,n] 的子区间。(这些区间可作为数据结构题目的操作序列)
#include<bits/stdc++.h> #define int long long using namespace std; int m,n,x; signed main(){ srand(time(0)); cin>>m>>n; for(int i=1;i<=m;i++){ int l=rand()%n+1,r=rand()%n+1; if(l>r) swap(l,r); cout<<l<<" "<<r<<endl; } return 0; }
3. 随机生成树
目标:随机生成一棵 n 个点的树,用 n 个点 n-1 条边的无向图的形式输出,每条边附带一个 109 以内的正整数权值。
#include<bits/stdc++.h> #define int long long using namespace std; int n,x; signed main(){ srand(time(0)); cin>>n; for(int i=2;i<=n;i++){ int fa=rand()%(i-1)+1,val=rand()%(int)1e9+1; cout<<fa<<" "<<i<<" "<<val<<endl; //从 2~n 之间的每个点 i 向 1~i-1 之间的点连一条边 } return 0; }
4. 随机生成图
目标:随机生成一张 n 个点 m 条边的无向图,图中不存在重边、自环,且必须连通,保证 5≤n≤m≤n×(n-1)/4≤106。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+5; int n,m; pair<int,int>e[N]; //保存数据 map<pair<int,int>,bool>h; //防止重边 signed main(){ srand(time(0)); cin>>n>>m; //先生成一棵树,保证连通 for(int i=1;i<n;i++){ int fa=rand()%i+1; e[i]=make_pair(fa,i+1); h[e[i]]=h[make_pair(i+1,fa)]=1; } //再生成剩余的 m-n+1 条边 for(int i=n;i<=m;i++){ int x,y; do{ x=rand()%n+1,y=rand()%n+1; }while(x==y||h[make_pair(x,y)]); e[i]=make_pair(x,y); h[e[i]]=h[make_pair(y,x)]=1; } //随机打乱,输出 random_shuffle(e+1,e+1+m); for(int i=1;i<=m;i++) cout<<e[i].first<<" "<<e[i].second<<endl; return 0; }