poj2912 带权并查集

题目链接在这里

题目大意

有n个学生玩剪子包袱锤,其中有一个人是可以在剪子包袱锤中随意出,另外n-1个学生被分为3组,每一组只能固定出一个固定的(三组出的互不相同)。有m轮比赛。问经过m轮比赛后能不能判断出来谁是裁判。

想法

这是一个带权并查集问题,除去裁判之外有3类学生。我们可以在n个学生中枚举谁是裁判,比如说1是裁判,那么在m轮比赛里我们就忽略有关学生1的比赛,看剩下的有没有矛盾(比如0赢了2,后来2又赢了0),如果没有矛盾的话就说明学生1就是裁判,如果有矛盾的话,我们就记录下来它在第cn次比赛出现矛盾(代表着在第cn轮比赛中判断出来的1不是裁判)。如果仅有一个裁判的话,我们就取各cn中的最大值作为答案输出。

代码如下

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define clr(x) memset(x, 0, sizeof(x))
#define rep(i, x) for(int i = 0; i < x; ++i)
using namespace std;

const int MaxN = 510;
const int MaxM = 2010;

struct Node{
    int x, y;
    char ch;
}node[MaxM];

int n, m;
int par[MaxN], Rank[MaxN];

void init(){
    rep(i, MaxN)    par[i] = i;
    clr(Rank);
}

int Find(int x){
    if(x == par[x])    return x;
    int tmp = par[x];
    par[x] = Find(par[x]);
    Rank[x] = (Rank[x] + Rank[tmp]) % 3;
    return par[x];
}

bool unite(int x, int y, int n){
    int fx = Find(x);
    int fy = Find(y);

    if(fx == fy){
        if(n && (Rank[y] + 1) % 3 != Rank[x])   return false;
        if(!n && Rank[x] != Rank[y])    return false;
        return true;

    }
    par[fx] = fy;
    Rank[fx] = (n + Rank[y] - Rank[x] + 3) % 3;
    return true;
}

void solve(){
    int cnt[MaxN];
    clr(cnt);

    rep(pe, n){
        //cout << pe << "是裁判" << endl;
        init();
        int flag;
        rep(i, m){
            if(node[i].x == pe || node[i].y == pe)  continue;
            if(node[i].ch == '=')
                flag = unite(node[i].x, node[i].y, 0);
            else
                flag = unite(node[i].x, node[i].y, 1);
            /**************************************************************/
            //printf("Rank[%d]:%d, Rank[%d]:%d\n", node[i].x, Rank[node[i].x], node[i].y, Rank[node[i].y]);
            if(!flag){
                cnt[pe] = i + 1;    //第i局判断出来pe不是裁判
                break;
            }
        }
    }

    int num = 0;    //计数有多少个人被判断为裁判
    int p;
    rep(i, n)
        if(cnt[i] == 0){
            ++num;
            p = i;
        }
    if(num > 1)
        cout << "Can not determine" << endl;
    if(num == 1){
        int Max = 0;
        rep(i, n)   Max = max(Max, cnt[i]);
        cout << "Player " << p << " can be determined to be the judge after " << Max << " lines" << endl;
    }
    if(num == 0)
        cout << "Impossible" << endl;
}

int main(){
    ios::sync_with_stdio(false);
    while(cin >> n >> m){
        rep(i, m){
            cin >> node[i].x >> node[i].ch >> node[i].y;

            if(node[i].ch == '>'){
                node[i].ch = '<';
                node[i].x ^= node[i].y;
                node[i].y ^= node[i].x;
                node[i].x ^= node[i].y;
            }
        }
        solve();
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值