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\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; }