HDU3635 Dragon Balls

并查集初级题目

题目链接:点击打开链接

题意:

1、每个城市初始有一个龙珠,father[i] = i初始化数组,

2、每个城市的龙珠可以移动,T A B 包含A龙珠的城市的所有龙珠都转移到包含B龙珠的城市中去

3、Q X,输出X龙珠所在城市、所在城市拥有的龙珠数量、X龙珠被移动过的次数

思路:

简单并查集,但是考虑到路径压缩会造成X龙珠移动次数计算错误(详见百度并查集路径压缩原理),所以不进行路径压缩,

直接使用一个数组c[MAXN]来记录每个地点(而不是龙珠)被移动过的次数,最后通过遍历(搜索你的根节点),每次加上经过地点的权重。

 

#include<stdio.h>
#include<iostream>
using namespace std;
int father[10005];
int c[10005];
int size[10005];
void init(int n)//初始化
{
    for(int i = 1 ; i <= n ; i ++)
    {
        father[i] = i;
        c[i] = 0;
        size[i] = 1;
    }
}
int find(int x)//由于路径压缩有后遗症
{//因此不进行路径压缩
    int i = x;
    while(father[i] != i)
    {
        i = father[i];
    }
    return i;
}
int f(int x)
{//使用函数求一个每个球走过的地方
//对于每个球来说,遍历数组,他走过的路径为每个地点的c[i]值
    int i = x;
    int ans = 0;
    while(father[i] != i)
    {
        ans += c[i];
        i = father[i];
    }
    return ans;
}
void merge(int x,int y)
{//合并操作,同时计算每个地点有几个球
    int fx = find(x);
    int fy = find(y);
    size[fy] += size[fx];
    size[fx] = 0;
    if(fx!=fy)
    {
        father[fx] = fy;
    }
}
int main()
{
    int n,m;
    int x,y;
    int T;
    scanf("%d",&T);
    int kk = T;
    while(T--)
    {
        scanf("%d %d",&n,&m);
        printf("Case %d:\n",kk-T);
        init(n);
        for(int i = 1 ; i <= m; i ++)
        {
            char t;
            int a;
            getchar();
            scanf("%c",&t);
            if(t == 'T')
            {
                scanf("%d %d",&x,&y);
                c[find(x)]++;//对应每一个地点使用次数加一
                merge(x,y);
            }
            else if(t == 'Q')
            {
                scanf("%d",&a);
                printf("%d %d %d\n",find(a),size[find(a)],f(a));

            }
        }
    }
    return 0;
}


 

你可能感兴趣的:(HDU3635 Dragon Balls)