POJ ~ 2912 ~ Rochambeau (枚举+并查集)

题意:你在看N个小孩在玩石头剪刀布,编号为0 ~ n-1,每个小孩会一直出同一种手势(如果出石头就一直出石头),但是这些小孩中有一个法官,法官想出什么手势就出什么手势。他们总共玩了M局游戏(1~M),a<b表示a输给了b,a>b表示a赢了b,a=b表示平局。问你能否发现这些孩子中的法官,如果发现了是在第几局游戏中发现的?

在解释一下问的内容:

1.”Impossible“谁当法官都不可以使全部对局成立。

2.”Player %d can be determined to be the judge after %d lines“,只有一个法官可以是全部对局成立,编号为%d孩子是法官,你是在第%d局发现的,也就是在第几行你把其他可能的法官,都给推翻了。

3.“Can not determine”表示多个孩子做法官都可以使所有对局成立,你就无法判断哪个孩子是法官了。


思路:枚举每个孩子做法官,初始化并查集,忽略法官在的局。然后看有没有错误,①如果没有,法官数+1,法官编号等于当前的法官

②如果有错误,记录下来第一个错误的地方,跟之前的第一个错误的地方取一个最大值。因为:假设法官只有一个是3号,在前6局的时候,你判断出来2,3,4都可能是法官,你在第7局判断2号不可能是法官,在第9局判断出来4号不可能是法官,那么在第9局你就判断出来了3号是法官。

所以输出”Player 3 can be determined to be the judge after 9 lines。

如果法官数==0,也就是谁当法官都不可以使全部对局成立,输出Impossible

如果法官数==1,只有一个法官输出Player %d can be determined to be the judge after %d lines“,编号为%d孩子是法官,你是在第%d局发现的

如果法官数>=2,有多个人当法官都可以使全部对局成立,则不能判断谁是法官,输出”Can not determine


//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN = 505;
const int MAXM = 2005;
int n, m, wa, f[MAXN], w[MAXN];//并查集数组和关系数组
//0:相同 1:赢 2:输
struct In
{
    int a, b;
    char op;
}in[MAXM];//输入
void init()
{
    wa = 0;
    for (int i = 0; i <= n; i++)
    {
        f[i] = i; w[i] = 0;
    }
}
int Find(int x)
{
    if (f[x] == x) return x;
    int t = f[x];
    f[x] = Find(f[x]);
    w[x] = (w[x] + w[t]) % 3;
    return f[x];
}
void Union(int a, int b, int D)
{
    int root1 = Find(a), root2 = Find(b);
    if (root1 != root2)
    {
        f[root1] = root2;
        w[root1] = (w[b] + D - w[a] + 3) % 3;
    }
    else
    {
        if ((w[a] - w[b] + 3) % 3 != D) wa++;
    }
}
int main()
{
    while (~scanf("%d%d", &n, &m))
    {
        if (m == 0) { printf("Player 0 can be determined to be the judge after 0 lines\n"); continue; }
        for (int i = 0; i < m; i++) scanf("%d%c%d", &in[i].a, &in[i].op, &in[i].b);//输入
        int cnt = 0, player = 0, line = 0;//可行的法官个数, 法官编号, 行数
        for (int i = 0; i < n; i++)//枚举每个人做法官
        {
            init();//初始化
            for (int j = 0; j < m; j++)//
            {
                if (in[j].a == i || in[j].b == i) continue;//有法官的局跳过
                if (in[j].op == '=') Union(in[j].a, in[j].b, 0);//a,b平局
                else if (in[j].op == '>') Union(in[j].a, in[j].b, 1);//a赢b
                else if (in[j].op == '<') Union(in[j].a, in[j].b, 2);//a输b
                if (wa == 1) { line = max(line, j + 1); break; }//错误的地方
            }
            if (wa == 0) { cnt++; player = i; }
        }
        if (cnt == 0) printf("Impossible\n");//谁当都不行
        else if(cnt == 1) printf("Player %d can be determined to be the judge after %d lines\n", player, line);//只有一个裁判
        else if(cnt >= 2) printf("Can not determine\n");//找不到(即有多个人当裁判都可以)
    }
    return 0;
}
/*
3 3
0<1
1<2
2<0
3 5
0<1
0>1
1<2
1>2
0<2
4 4
0<1
0>1
2<3
2>3
1 0
*/
/*
Can not determine
Player 1 can be determined to be the judge after 4 lines
Impossible
Player 0 can be determined to be the judge after 0 lines
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值