标签:
2 3 3 T 1 2 T 3 2 Q 2 3 4 T 1 2 Q 1 T 1 3 Q 1
Case 1: 2 3 0 Case 2: 2 2 13 3 2
题意:题意:刚开始每个city都有一个对应编号的球,现在给出2个命令,一个是T A B 将A所在的城市里的所有球转移到B球所在的城市, 一个是C A 要求输出A球所在的城市的编号和该城市共有多少个球,以及A球被转移的次数。 思路:首先这里刚开始球的编号和城市的编号一一对应,要想到并查集的方法,其次对于T命令的操作就是合并A和B的城市, 只要将统计城市球数的数组更新一下即可,并对A城市的根节点所在的球的转移次数设置为1 , 因为显然这个根节点所对应的球是第一次被转移,难点在于其他的球的转移次数需要根据这个根节点的转移次数来求出。 关键就是路径压缩了,要想求某个球的转移次数,需要对它进行路径的更新, 一直更新到它的根节点,根据根节点的转移次数为1,回溯递推出要求的球的转移次数。 加权并查集,,递归的过程好难理解。 2015,7,23
#include<stdio.h> #include<string.h> #define M 10100 int f[M],time[M],city[M];//分别存放,父节点,转移次数,城市里边的珠子总数 void init() { for(int i=0;i<M;i++){ f[i]=i;//父节点初始化为自己 city[i]=1;//开始的时候每个城市有一个球 time[i]=0; } } int find(int k) { if(f[k]!=k) { int temp=find(f[k]);//找到根节点 time[k]+=time[f[k]];//子节点的转移次数加上父节点的转移次数 f[k]=temp;//压缩路径,父节点直接指向根节点 } return f[k]; } void merge(int a,int b) { int x=find(a); int y=find(b); if(x!=y) { f[x]=y; time[x]=1;//第一次转移 city[y]+=city[x]; city[x]=0; } } int main() { int t,v=1,i,a,b,c,n,m; char ch[5]; scanf("%d",&t); while(t--) { init(); printf("Case %d:\n",v++); scanf("%d%d",&n,&m); for(i=0;i<m;i++) { scanf("%s",ch); if(ch[0]=='Q') { int k; scanf("%d",&c); k=find(c); printf("%d %d %d\n",k,city[k],time[c]); } if(ch[0]=='T') { scanf("%d%d",&a,&b); merge(a,b); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/ling_du/article/details/47028717