POJ - 2912 Rochambeau (带权并查集+枚举)

题意:有N个人被分为了三组,其中有一个人是开了挂的。同组的人的关系是‘=’,不同组的人关系是‘<’或'>',但是开了挂的人可以给出自己和他人任意的关系。现在要根据M条关系找出这个开了挂的人。M条关系中可能有多组异常信息。可能会有多个人是外挂,也可能找不出外挂,如果能找到,则要输出其编号X和最早能确定他身份的前Y组条件。

分析:和食物链那题性质很像,但是食物链只需要判断条件对错,而本题是要根据正确性不明的信息找出答案。

还是用模3系的带权并查集解决该问题。枚举每个人i不是外挂的情况,对每一种情况,用不含i的关系去验证,出现矛盾则表示排除了i之外的其他中外挂,记录出现错误的关系编号。

取N-1个人发生验证时发生错误的最大关系编号,就可以推断出谁是外挂了。

如果每个人都不出现错误,则是不可能的情况;如果有多人可以是外挂,则不能找出;否则输出答案。

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn =2e3+5;
int fa[maxn],num[maxn];
int pos[maxn];                  //错误发生的编号
void init(int N){
    for(int i=0;i<=N;++i){
        fa[i]=i;
        num[i]=0;
    }
}
//模3系
inline int Find(int x){
    if(fa[x]==x) return x;
    int f = fa[x];
    fa[x] = Find(fa[x]);
    num[x] = (num[x]+num[f])%3;
    return fa[x];
}
bool Union(int a,int b,int op)
{
    int roota = Find(a),rootb =Find(b);
    if(roota==rootb){
        if((num[a]+op)%3!=num[b]) return false;
        else return true;
    }
    fa[rootb] = roota;
    num[rootb] = (-num[b]+num[a]+op+3)%3; 
    return true; 
}
struct Query{
    int a,b,op;
}p[maxn];

int main(){
    #ifndef ONLINE_JUDGE
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
    #endif
    int N,M,T,Q,u,v,tmp,cas=1,a,b;
    char op;
    while(scanf("%d%d",&N,&M) == 2 ){
        memset(pos,-1,sizeof(pos));
        for(int i=1;i<=M;++i){
            scanf("%d%c%d",&p[i].a,&op,&p[i].b);
            if(op=='=') p[i].op=0;
            if(op=='<') p[i].op=1;
            if(op=='>') p[i].op=2;
        }
        for(int i=0;i<N;++i){               //尝试枚举每个人不是judge的可能
            init(N);
            for(int j=1;j<=M;++j){
                if(i==p[j].a || i==p[j].b) continue;        //跳过包含i的条件
                if(!Union(p[j].a,p[j].b,p[j].op)) {
                    pos[i]=j;
                    break;                          //找到错误的发生即可推断出judge在i之外的人中
                }
            }
        }
        int cnt=0,ans1=0,ans2=0;
        for(int i=0;i<N;++i){
            if(pos[i]==-1){                     //如果排除这个人不会产生问题,那么他就可以是judge
                cnt++;
                ans1 = i;
            }
            ans2 = max(ans2,pos[i]);            //推断n-1个人不是judge之后,也就知道了谁是judge
        }
        if(cnt>1) printf("Can not determine\n");
        else if(cnt==0) printf("Impossible\n");
        else printf("Player %d can be determined to be the judge after %d lines\n",ans1,ans2);
    }
    return 0;
}

 

posted @ 2018-08-04 11:12  xiuwenL  阅读(149)  评论(0编辑  收藏  举报