AKOJ-2010-魔法石

链接:https://oj.ahstu.cc/JudgeOnline/problem.php?id=2010

题意:

Vyoung最近收集到一大批魔法石,这些魔法石有两种特性,攻击和防守,不同特性的两个魔法石可以组合在一起形成威力巨大的武器(正确的组合),现在给你m对魔法石,检查其中有多少对与之前的组合矛盾,即组合错误的魔法石

注意组合错误即是:相同特性的魔法石是一个组合,或者自己与自己组合

思路:

带权并查集,才学的成果。

Rank数组保存i与Father[i]的关系。因为只有两种,所以用0表示同种,1表示不同种。

同理,找父亲的时候更新Rank数组。因为每个位置与父节点肯定是不同,所以初始为1。

每个点与父节点的关系,加上父节点与根节点的关系,mod2,即为每个点与根节点的关系。

而合并连个集合时。因为两个点的关系肯定为1,所以找到每个点与父节点的关系即可。

代码:

#include <iostream>
#include <memory.h>
#include <string>
#include <istream>
#include <sstream>
#include <vector>
#include <stack>
#include <algorithm>
#include <map>
#include <queue>
#include <math.h>
using namespace std;
const int MAXN = 50000+10;
int Father[MAXN],Rank[MAXN];
int n,m;

void Init()
{
    for (int i = 1;i<=n;i++)
    {
        Father[i] = i;
        Rank[i] = 0;
    }
}

int Get_F(int x)
{
    if (Father[x] == x)
        return x;
    int tmp = Father[x];
    Father[x] = Get_F(Father[x]);
    Rank[x] = (Rank[x] + Rank[tmp])%2;//当前点与根节点的关系为当前点与父节点和父节点与根节点
    return Father[x];
}

void Union(int l,int r)
{
    int fl = Get_F(l);
    int fr = Get_F(r);
    Father[fr] = fl;
    Rank[fr] = (Rank[l] + 1 + Rank[r])%2;
}

int main()
{
    int t;
    int cnt = 0,sum;
    int l,r;
    scanf("%d",&t);
    while (t--)
    {
        sum = 0;
        scanf("%d%d",&n,&m);
        Init();
        for (int i = 1;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            int fl = Get_F(l);
            int fr = Get_F(r);
            if (fl == fr && Rank[l] == Rank[r])
                sum++;
            else
                Union(l,r);
        }
        printf("Case #%d: %d\n",++cnt,sum);
    }


    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/YDDDD/p/10301700.html