論OI中幾種常見的資料生成方法
阿新 • • 發佈:2019-01-26
零、前言
為了保證程式的正確,我們需要生成資料進行檢驗,這就需要使用到資料生成器.
本文就講講怎麼生成幾種OI中的常見資料.
一、排列
1、問題:給定N,在O(n) 隨機出1—N的一個排列
2、STL
- 時間複雜度:
O(N) - 程式碼:
int t[N];
void makePerm0(void)
{
for (int i=1;i<=n;i++) t[i]=i;
random_shuffle(t+1,t+n+1);
}
- 解釋:呼叫STL的random_shuffle(F,S),可以直接對地址為F到地址為S的位置打亂順序.
3、隨機交換
- 時間複雜度:
O - 做法:首先隨機出1—N的一個排列,然後對於第i位,把它和p[rand()%(i-1)+1]進行交換.
- 程式碼:
int t[N];
void makePerm1(void)
{
srand(time(0));
for (int i=1;i<=n;i++) t[i]=i;
for (int i=2;i<=n;i++) swap(t[i],t[rand()%(i-1)+1]);
}
- 注意:P黨就只能用第二種了,不過也差不多…
二、樹
1、問題:在O(n) 內生成一棵樹
2、方法:往前連邊
- 對於第i個點,我們把它往前連到rand()%(i-1)+1
- 程式碼:
void makeTree0(void)
{
srand(time(0));
for (int i=2;i<=n;i++)
printf("%d %d\n",i,rand()%(i-1)+1);
}
- 證明:樹就是無向無環聯通圖.
現在要證明它是無環的,且整棵樹聯通.
①當n=2時,滿足要求,因為2必定連到1
②假設當n<k 時都滿足,證明當n=k 時亦滿足
∵ 連向的點c滿足1<c<k
∴ 不會產生迴路
又∵ 之前全都連在一起
∴ 現在也連在一起
綜上所述,該演算法可以在O(n) 內構造出樹.
3、特殊要求
如果要求1不一定是根,怎麼辦?
我們進行一次makePerm,往回連的時候把t[i]連到t[rand()%(i-1)+1].
三、圖
1、問題:在O(m) 內生成一張聯通圖
2、方法:首先建樹,然後剩下的邊隨便
3、特殊要求
- 要求1:沒有重邊
①對於N比較大的情況,每次隨機,每次生成的邊加到set或者Hash裡面
②對於N比較小的情況,把所有的邊(u,v)列出來,用random_shuffle()隨機二元組 - 要求2:沒有自環:遇到自環就重新來
- 要求3:規定起點,終點連通的有向圖
①首先t[1]=s,隨機t[2]到t[n],然後把t[1],t[2],t[3],…,ti進行連邊
②對於後面的點,隨機連到前面,方向也進行隨機
③最後隨便弄一些邊,完善這一棵樹
int t[N],s,t;
void makeGraph(void)
{
for (int i=1;i<=n;i++) t[i]=i;
random_shuffle(t+1,t+n+1);
for (int i=1;i<=n;i++) if (t[i]==s) {swap(t[i],t[1]);break;}
int i;
for (i=1;i<n;i++)
{
printf("%d -> %d",t[i],t[i+1]);
if (t[i+1]==t) break;
}
int k;
for (i++;i<n;i++)
{
k=rand()&1;
if (!k)
printf("%d -> %d\n",t[i],t[rand()%(i-1)+1]);
else printf("%d -> %d\n",t[rand()%(i-1)+1],t[i]);
}
}
4、字串
1、問題:在
2、方法
char s[L]; int len;
int makeString(void)
{
for (int i=1;i<=len;i++) s[i]=rand()%M+N;
//M為個數,N為起始字元
}
5、小結
一些常見的資料生成方法上面已經涉及,今天就總結這麼多啦!