南阳1022——合纵连横(并查删)
Posted li-yaoyao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了南阳1022——合纵连横(并查删)相关的知识,希望对你有一定的参考价值。
题目: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();//将上一行的‘ ‘去掉 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 ",++c,sum); 73 } 74 return 0; 75 }
以上是关于南阳1022——合纵连横(并查删)的主要内容,如果未能解决你的问题,请参考以下文章