HDU 3635 Dragon Balls

题目地址:

http://acm.hdu.edu.cn/showproblem.php?pid=3635


题目类型: 并查集


题目:

Five hundred years later, the number of dragon balls will increase unexpectedly, so it's too difficult for Monkey King(WuKong) to gather all of the dragon balls together.

HDU 3635 Dragon Balls
His country has N cities and there are exactly N dragon balls in the world. At first, for the ith dragon ball, the sacred dragon will puts it in the ith city. Through long years, some cities' dragon ball(s) would be transported to other cities. To save physical strength WuKong plans to take Flying Nimbus Cloud, a magical flying cloud to gather dragon balls.
Every time WuKong will collect the information of one dragon ball, he will ask you the information of that ball. You must tell him which city the ball is located and how many dragon balls are there in that city, you also need to tell him how many times the ball has been transported so far.


样例输入:

  
  
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 1 3 3 2


题目大意:

有N的龙珠,编号为1~N,开始时分别分布在编号为1~N的城市。

然后如果是输入T a b,那么进行移动, 把编号a的龙珠所在的城市的所有龙珠移动到编号b龙珠所在的城市。

输入Q a, 那么输出a龙珠所在的城市, a龙珠所在城市有的龙珠的个数, 以及a龙珠移动的次数。


思路与总结:

首先,感觉这题确实是一道很好的并查集题目,可以加深对并查集和压缩路径的理解。

做这题有点略纠结,WA了很多次,说明我对并查集的理解还是不够。

求一个龙珠在那个城市很好办, 只需要find(x),找到x的根结点,即是x所在的城市

求一个城市有多少个龙珠也很好办, 只需要加上一个rank数组,用来表示并查集的秩,及树的高度,就是那个城市的龙珠的数量。

而求一个龙珠移动的次数,比较难搞,也正式我纠结之处。


首先,当一座城市的龙珠全部移动到另一个城市之后,那么这个城市的龙珠数量变为0, 也就是说没有龙珠是在这个城市了,那么之后都不会再有龙珠移动到

这个空城市。因为T a x,必须是移动到龙珠x所在的城市,而现在已经没有龙珠落在空城市了,对于任意龙珠x,都不会是落在空城市。最后可以得出结论,一个

城市只能移动一次。

开一个数组num表示各个求的移动次数。

每次移动时, 设是T a b, 那么b所在城市(即b的根结点)的最初始的球, 是这个球的第一次移动, 这时给初始球的移动次数置为1。

光光是这样做的话,还不够。因为这样只增加了根结点的初始那个球的次数,还有其他球在这个跟结点的次数还没有加。


别急, 这个这个步骤可以留给路径压缩的时候做。

还没进行路径压缩时,它的父亲是以前的那个跟结点,而这时候,之前欠下来的债也还了,让它的移动次数加上它所有祖宗的移动次数(这个是关键,也比较

难理解)。

最后,它只想了新结点。 次数也跟新了。

进行路径压缩之后,每个球的父亲结点就是它所在的城市。


#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 10002
using namespace std;
int N, Q, father[MAXN], rank[MAXN], num[MAXN];

void init(){
    for(int i=1; i<=N; ++i){
        father[i] = i, rank[i] = 1, num[i]=0;
    }
}

int find(int x){
    if(x==father[x]) return x;
    int t=father[x];
    father[x] = find(father[x]);
    num[x] += num[t];
    return father[x]; 
}

void Union(int x,int y){
    int a=find(x);
    int b=find(y);
    if(a!=b){
        father[a] = b;
        rank[b] += rank[a];
        num[a] = 1; // 这是球a第一次移动
    }
}


int main(){
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif
    int T,a,b,k,cas=1;  char cmd[2];
    scanf("%d", &T);
    while(T--){
        printf("Case %d:\n",cas++);
        scanf("%d %d", &N,&Q);
        init();
        for(int i=0; i<Q; ++i){
            scanf("%s", cmd);
            if(cmd[0]=='T'){
                scanf("%d %d", &a, &b);
                Union(a, b);
            }
            else{
                scanf("%d", &k);
                int x = find(k);
                int cnt=0;
                printf("%d %d %d\n", x, rank[x],num[k]); 
            }
        }
    }
    return 0;
}



—— 生命的意义,在于赋予它意义。

原创 http://blog.csdn.net/shuangde800 By D_Double





你可能感兴趣的:(drag)