POJ2912 Rochambeau —— 种类并查集 + 枚举

题目链接:http://poj.org/problem?id=2912

 

Rochambeau
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 3663   Accepted: 1285

Description

N children are playing Rochambeau (scissors-rock-cloth) game with you. One of them is the judge. The rest children are divided into three groups (it is possible that some group is empty). You don’t know who is the judge, or how the children are grouped. Then the children start playing Rochambeau game for M rounds. Each round two children are arbitrarily selected to play Rochambeau for one once, and you will be told the outcome while not knowing which gesture the children presented. It is known that the children in the same group would present the same gesture (hence, two children in the same group always get draw when playing) and different groups for different gestures. The judge would present gesture randomly each time, hence no one knows what gesture the judge would present. Can you guess who is the judge after after the game ends? If you can, after how many rounds can you find out the judge at the earliest?

Input

Input contains multiple test cases. Each test case starts with two integers N and M (1 ≤ N ≤ 500, 0 ≤ M ≤ 2,000) in one line, which are the number of children and the number of rounds. Following are M lines, each line contains two integers in [0, N) separated by one symbol. The two integers are the IDs of the two children selected to play Rochambeau for this round. The symbol may be “=”, “>” or “<”, referring to a draw, that first child wins and that second child wins respectively.

Output

There is only one line for each test case. If the judge can be found, print the ID of the judge, and the least number of rounds after which the judge can be uniquely determined. If the judge can not be found, or the outcomes of the M rounds of game are inconsistent, print the corresponding message.

Sample Input

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

Sample Output

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

Source

Baidu Star 2006 Preliminary 
Chen, Shixi (xreborner) living in http://fairyair.yeah.net/
 
 
 
题解:
1.运用种类并查集以判断每个人的关系。
2.自己一开始的尝试是:一边读入一边处理,看是否能找到裁判,怎么找呢?在读入一条数据之后尝试合并,如果在合并的过程中出现冲突,那么就可以确定,裁判一定在u到v这条路径上……………………,抛开其他的细节,单单是一点,就让这个尝试胎死腹中:每次出现冲突,根节点肯定在路径上,再加上u、v,共三个点且至少三个点,那又怎么确定谁是裁判呢?
3.尝试失败的原因:没有搞清楚并查集能干些什么,把一道题目的许多功能都寄希望于并查集上。
4.那并查集能干些什么:1.确定集合中元素之间的关系(具体关系);2.路径压缩,效率上的优化。
5.对于此题,如果能确定这个唯一的裁判,那么:如果出现混乱,那么裁判在集合中。换句话说,如果裁判不出现,那么就不会出现混乱。(突然想到离散数学的逻辑证明: p->q 等价于 !q->!p)。
6.基于以上一点,我们尝试枚举每一个人作为裁判,每一个裁判都重新进行一次并查集。如果在处理的过程出现冲突,那么就可以排除这个人是裁判。当可能是裁判的人的个数为1时,就可以确定这唯一的人就是裁判。算法复杂度:O(n*m*k),其中计算次数为 case*1e6*k,其中k为并查集的find()函数复杂度,很小。所以此方法可行。
7.如果可以确定谁是裁判,那么又怎么知道处理完几条数据之后就能确定裁判呢?当排除完其他人都不是裁判时,裁判是谁就自然显露出来了。所以取所有出现冲突时,数据下标的最大值。
 
 
学习之处:
特殊对象的特殊处理:当一个对象的出现会引起某种现象的出现。为了能够找到这个对象,我们可以把它隔离开来,那么这种现象就不会出现了。
根据的原理:离散数学中的逻辑证明:p->q 等价于 !q->!p
设p为出现这种现象, q为这个对象在集合中。
p->q:如果出现了这个现象,那么这个对象就在集合中
!q->!p:如果这个对象不在集合中, 那么没有出现这种现象。
以上两个命题是等价的,也可以说是逆向思维吧。
 
 
代码如下:
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 #define ms(a,b) memset((a),(b),sizeof((a)))
13 using namespace std;
14 typedef long long LL;
15 const double EPS = 1e-8;
16 const int INF = 2e9;
17 const LL LNF = 2e18;
18 const int MAXN = 1e3+10;
19 
20 int n, m;
21 int fa[MAXN], r[MAXN];
22 struct node
23 {
24     int u, v, w;
25 }a[2020];
26 
27 int find(int x)
28 {
29     if(fa[x]==-1) return x;
30     int pre = find(fa[x]);
31     r[x] = (r[x]+r[fa[x]])%3;
32     return fa[x] = pre;
33 }
34 
35 bool Union(int u, int v, int w)
36 {
37     int fu = find(u);
38     int fv = find(v);
39     if(fu==fv)
40         return ((3-w+r[u])%3!=r[v]);
41 
42     fa[fu] = fv;
43     r[fu] = (3-r[u]+w+r[v])%3;
44     return false;
45 }
46 
47 int main()
48 {
49     while(scanf("%d%d", &n, &m)!=EOF)
50     {
51         for(int i = 1; i<=m; i++)
52         {
53             char ch;
54             scanf("%d%c%d", &a[i].u, &ch, &a[i].v);
55             if(ch=='=') a[i].w = 0;
56             if(ch=='<') a[i].w = 1;
57             if(ch=='>') a[i].w = 2;
58         }
59 
60         int judge, index = 0, cnt = 0;  //judge为裁判的下标, index为找到裁判时的下标, cnt为可能是裁判的人的个数。
61         for(int k = 0; k<n; k++)    //枚举每一个人作为裁判
62         {
63             bool flag = true;
64             memset(fa, -1, sizeof(fa));
65             memset(r, 0, sizeof(r));
66             for(int i = 1; i<=m; i++)
67             {
68                 int u = a[i].u, v = a[i].v, w = a[i].w;     //其中一个人是“裁判”, 则不作处理
69                 if(u==k || v==k) continue;
70 
71                 if(Union(u, v, w))  //出现冲突,排除这个人是裁判
72                 {
73                     /**找到裁判时的下标,取所有发生冲突时,下标的最大值。为什么?
74                     当排除完其他人都不是裁判时,裁判是谁就自然显露出来了 **/
75                     index = max(index, i);
76                     flag = false;
77                     break;
78                 }
79             }
80 
81             if(flag)    //如果跳过了k后,其他人的关系都不会发生冲突, 那么k就有可能是裁判
82             {
83                 judge = k;
84                 cnt++;  //更新个数
85             }
86         }
87 
88         if(cnt==0)  //可能是裁判的人的个数为0:谁都不可能是裁判
89             printf("Impossible\n");
90         else if(cnt>1)  //可能是裁判的人的个数大于1:不能确定谁是裁判
91             printf("Can not determine\n");
92         else        //可能是裁判的人的个数等于1:这个人就是裁判
93             printf("Player %d can be determined to be the judge after %d lines\n", judge, index);
94     }
95 }
View Code

 

posted on 2017-10-13 15:59  h_z_cong  阅读(397)  评论(0编辑  收藏  举报

导航