1. 程式人生 > >南陽1022——合縱連橫(並、查、刪)

南陽1022——合縱連橫(並、查、刪)

while 區域 class 初始化 如果 col case 數組 除了

題目:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=1022

想法:比 親戚這一題難,因為還涉及到 退出 即 解除關系 問題,除了find()、combine()函數還新加一個刪除delet()函數。

人(諸侯國)先坐在箱子裏,然後連箱子,最後某個人要退出時,直接從箱子裏出來,坐到新的箱子裏去(刪),這樣,之前如果有許多其他的人連在要退出的人身上,其他人的關系依然在,因為箱子還在

註意:第一次runtime error ,提示到:數組開得太小了,導致訪問到了不該訪問的內存區域;我就將max=100005擴大到max=1000005,結果就過了,但不知道為什麽數組要開這麽大?

代碼:

 1 #include<stdio.h>
 2 #include<memory.h>
 3 #define max 1000005
 4 int f[2*max],box[2*max],mark[max];//f[x]=a指 標號為x的箱子 連接到標號為a的箱子,box[x]=i,x這個人坐在標號為i的箱子裏,mark[i]記錄i是否為根源
 5 //
 6 int find(int a) //查,查a連接在哪個上面
 7 {
 8     if(f[a]!=a)//說明還沒有找到最上面的箱子(就是f[a]==a的箱子,f[a]==a表示的是a鉤在a上,即發散的根源了)
 9         f[a]=find(f[a]);//
查詢並壓縮 10 return f[a]; 11 } 12 // 13 void combine(int x,int y) //並,將標號為x,y的箱子連接 14 { 15 int a,b; 16 a=find(x); 17 b=find(y); 18 if(a!=b)//兩箱子連接的根源箱子不一樣 19 f[a]=b;//讓兩者的根相連,避免有些箱子丟掉了根,去連別人了 20 else return; 21 } 22 // 23 void delet(int i,int k) //刪除i人,重新拿一個沒用過的箱子來,標號為k 24 { 25 box[i]=k;//
將i這個人放在 標號為k的箱子裏 26 f[k]=k;//這個箱子鉤在自己身上 27 return; 28 } 29 int main() 30 { 31 char ch; 32 int a,b,i,n,m,k,c=0,sum; 33 while(~scanf("%d %d",&n,&m)) //n個國家,m種操作 34 { 35 //初始化 36 sum=0; 37 memset(mark,0,sizeof(mark)); 38 for(i=0; i<n; i++) 39 { 40 box[i]=i;//i這個人,坐在編號為i的box裏 41 f[i]=i;//box[i]這個箱子連在標號為i的箱子上 42 } 43 k=n;//新的box的下標(之前初始化用到了n-1) 44 //輸入 45 for(i=0; i<m; i++) 46 { 47 getchar();//將上一行的‘\n‘去掉 48 scanf("%c",&ch); 49 if(ch==U) //合並 50 { 51 scanf("%d %d",&a,&b); 52 combine(box[a],box[b]); 53 } 54 if(ch==D) //退出 55 { 56 scanf("%d",&a);//a退出 57 delet(a,k); 58 k++; 59 } 60 } 61 62 //求共有幾個集合 63 for(i=0; i<n; i++) 64 { 65 a=find(box[i]); 66 if(!mark[a]) //說明它是新的根 67 { 68 mark[a]=1;//a這個根已經產生了,標記一下 69 sum++; 70 } 71 } 72 printf("Case #%d: %d\n",++c,sum); 73 } 74 return 0; 75 }

南陽1022——合縱連橫(並、查、刪)