POJ-2912 Rochambeau (带权并查集+暴力)

题意:剪刀石头布游戏:n个人(编号0~n-1) m 组数据,其中一个为judge,剩下的分为3组,有的组可能没有人,相同组的人出的手势相同,

其中judge出的姿势可以改变而其他人不能改变。最后判断谁是judge并且给出能判断的最小条件序号。

思路:POJ-1182 食物链 一样,都是涉及到多个种类的集合。我们假设一个每个人都有一个权值,用权值来记录其属于的不同集合。对于其关系从有向环的角度来看可以类比到mod运算中

(即循环)所以在合并时要对权值进行对应的合并。

对judge的判断:jduge这个角色会干扰到条件的判断,所以我们尝试假设排除某个人,保留其他人的关系然后判断是否冲突。可知冲突是judge导致的所以当

judge被排除时所给关系就不会冲突。如果所有人都不会导致冲突那么就不能判断谁是judge。而如果有多个人是judge那么就会全部冲突。根据前面三种情况来判断谁是judge。所以就for循环遍历

对最小条件序号判断:1)可知:所得条件序号一定是judge的条件 2)judge的条件必然会导致冲突  ;  所以从前面两个可推出,找到最大冲突序号即为所得

其他思路:

关于POJ-1182 食物链 事实上还有 开多倍空间的方法 即利用(1-n)(n-2n)(2n-3n)来表示不同状态

如果'<'则unite(a,b+n), unite(a+n,b+2n) ,unite(a+2n,b)

如果'>'则unite(b,a+n), unite(b+n,a+2n) ,unite(b+2n,a)

如股'='则unite(a,b), unite(a+n,b+n) ,unite(a+2n,b+2n)

完整代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define LL long long
using namespace std;

const int maxn =1e4+5;
int pre[maxn],rank[maxn];
int pos[maxn]; 
void init(int n){
    for(int i=0;i<=n;++i){
           pre[i]=i;
           rank[i]=0;
       }
}                
int find(int x){
    if(pre[x]==x) return pre[x];
    int fx = pre[x];
    pre[x] = find(pre[x]);
    rank[x] = (rank[x]+rank[fx])%3;
    return pre[x];
}
bool unite(int a,int b,int op)
{
    int fa = find(a),fb =find(b);
    if(fa==fb){
        if((rank[a]+op)%3!=rank[b]) return false;
        else return true;
    }
    pre[fb] = fa;
    rank[fb] = (-rank[b]+rank[a]+op+3)%3; 
    return true; 
}
struct node{
    int a,b,op;
}node[maxn];

int main(){
    char op;
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        memset(pos,-1,sizeof(pos));
        for(int i=1;i<=m;++i){
            scanf("%d%c%d",&node[i].a,&op,&node[i].b);
            if(op=='=') node[i].op=0;
            if(op=='<') node[i].op=1;
            if(op=='>') node[i].op=2;
        }
        //尝试枚举每个人不是judge的可能
        for(int i=0;i<n;++i){ 
            init(n);      
            for(int j=1;j<=m;++j){
                //跳过包含i的条件
                if(i==node[j].a || i==node[j].b) continue;  
                if(!unite(node[j].a,node[j].b,node[j].op)) {
                    pos[i]=j;
                    break;           
                }
            }
        }
        int cnt=0,ans1=0,ans2=0;
        for(int i=0;i<n;++i){
             //如果排除这个人不会产生问题,那么他就可以是judge
            if(pos[i]==-1){                    
                cnt++;
                ans1 = i;
            }
             //推断n-1个人不是judge之后,也就知道了谁是judge
            ans2 = max(ans2,pos[i]); 
        }
        if(cnt>1) printf("Can not determine
");
        else if(cnt==0) printf("Impossible
");
        else printf("Player %d can be determined to be the judge after %d lines
",ans1,ans2);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Tianwell/p/11202182.html