并查集/poj 2912 Rochambeau
题意
给出n种关系,有以下三种情况:
a>b :a赢了b
a<b :b赢了a
a=b :a与b平手
现在有三组人,出的手势是一定的,但是其中有一名judge,他可以出任意手势。问通过哪一行就可以推断出谁是judge。若没有则输出impossible。若有多个,则输出can not determine
分析
1.如何确定Judge
因为Judge可以任意出手势,所以凡是有关judge所建立起的关系都是不可靠的。
因此,我们可以枚举judge,凡是跟judge有关的关系都不考虑。如果此时建立起的关系有矛盾,则说明现在枚举到得人不是judge。
若有矛盾,则记录下在哪句话矛盾。此时,这句话即为判断该人为judge的一行。
若有若干个人枚举后无矛盾,即这些人作为judge时均无矛盾,则can not determine。
2.如何判断矛盾
利用并查集实现,将同一组的人归类,直到遇到矛盾。
具体归类方法和Noi2001食物链(poj1182)可以说一样,都是三种情况,具体分析请见
http://www.cnblogs.com/Rinyo/archive/2013/02/23/2923802.html 有详细分析
Accepted Code
1 /* 2 PROBLEM:poj2912 3 AUTHER:Rinyo 4 MEMO:并查集 5 */ 6 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 using namespace std; 11 const int MAXN=(505),MAXM(2005); 12 13 int f[MAXN],r[MAXN]; 14 int n,m,x[MAXM],y[MAXM]; 15 char d[MAXM]; 16 int judge,line,ans; 17 18 int find(int x) 19 { 20 if(x==f[x]) return x; 21 int temp=f[x]; 22 f[x]=find(temp); 23 r[x]=(r[temp]+r[x])%3; 24 return f[x]; 25 } 26 27 void merge(int x,int y,int d) 28 { 29 int fx=find(x),fy=find(y); 30 r[fx]=(r[y]-r[x]+d+3)%3; 31 f[fx]=fy; 32 } 33 34 int main() 35 { 36 freopen("poj2912.in","r",stdin); 37 while(~scanf("%d%d", &n, &m)) 38 { 39 for(int i=0;i<m;++i) 40 { 41 scanf("%d%c%d",&x[i],&d[i],&y[i]); 42 switch(d[i]) 43 { 44 case '=':d[i]=0;break; 45 case '>':d[i]=1;break; 46 case '<':d[i]=2;break; 47 } 48 } 49 judge=0;line=0;ans=0; 50 for(int i=0;i<n;++i) 51 { 52 for (int j=0;j<n;j++) {f[i]=i;r[i]=0;} 53 bool flag=true; 54 for(int j=0;j<m;++j) 55 { 56 if(x[j]==i || y[j]==i) continue; 57 int fx=find(x[j]),fy=find(y[j]); 58 if(fx == fy) 59 { 60 if(r[x[j]]!=(r[y[j]]+d[j])%3) 61 { 62 flag = false; 63 line=max(line,j+1); 64 break; 65 } 66 } 67 else merge(x[j],y[j],d[j]); 68 } 69 if(flag) 70 { 71 if(++ans>1) break; 72 judge=i; 73 } 74 } 75 if(ans==0) printf("Impossible\n"); 76 else if(ans==1) printf("Player %d can be determined to be the judge after %d lines\n",judge,line); 77 else printf("Can not determine\n"); 78 } 79 return 0; 80 }