POJ 2912 Rochambeau

题意:有一些人玩石头剪刀布,其中有一个人(称其为裁判)可以出“石头”,“剪刀”,“布”中的任意一个,其他人永远只能出相同的一个。即有的人只能出剪刀,有的人只能出石头,有的人只能出布。进行了多次对决,每次只告诉你谁赢了(或者平手),不说谁出了什么。问能否判断出谁是裁判,裁判有多少个?若只有一个裁判,问在进行了多少次对决以后就能判断出裁判是谁。

解法:首先,判断出裁判的方法是,若1,2,3号选手的结果出现了矛盾,则1,2,3号中必有一个人是裁判,

   (1)这个时候如果3,4号的对决结果出现矛盾,则判定3为裁判,然后还需要验证(即如果3为裁判,其他对决结果是不是不会有矛盾);

   (2)这个时候如果4,5号出现矛盾,则说明裁判不止一个人,与题设不符;

   (3)如果之后都再也没有出现矛盾,则说明不能判断出裁判是谁。

   所以,方法就是,枚举谁是裁判,判断是否所有不涉及到裁判的对决结果之间没有矛盾。如果只有一个裁判,还需要求进行了多少次对决以后就已经能判断出裁判是谁了。由以上结论不难看出,在整个枚举过程中,最大的出现矛盾的对决的编号数即为所求。

tag:并查集,good

  1 /*
  2  * Author:  Plumrain
  3  * Created Time:  2013-11-28 19:23
  4  * File Name: DS-POJ-2912.cpp
  5  */
  6 #include <iostream>
  7 #include <cstdio>
  8 #include <vector>
  9 
 10 using namespace std;
 11 
 12 #define PB push_back
 13 
 14 struct node{
 15     int f, r;
 16 };
 17 
 18 int n, m, line;
 19 node p[505];
 20 char xn[2005];
 21 vector<int> ans;
 22 int an[2005], bn[2005];
 23 
 24 int find (int x)
 25 {
 26     if (x != p[x].f){
 27         int y = p[x].f;
 28         p[x].f = find(y);
 29         p[x].r = (p[x].r + p[y].r) % 3;
 30     }
 31     return p[x].f;
 32 }
 33 
 34 void merge(int a, int b, char xx, int t1, int t2)
 35 {
 36     int x;
 37     if (xx == '=') x = 0;
 38     else if (xx == '>') x = 1;
 39     else x = 2;
 40 
 41     p[t1].f = t2;
 42     p[t1].r = (3 - p[a].r + x + p[b].r) % 3; 
 43 }
 44 
 45 bool ok(int a, int b, char xx)
 46 {
 47     int x;
 48     if (xx == '=') x = 0;
 49     else if (xx == '>') x = 1;
 50     else x = 2;
 51     
 52     return x == ((p[a].r + 3 - p[b].r) % 3);
 53 }
 54 
 55 bool gao(int x)
 56 {
 57     for (int i = 0; i < n; ++ i){
 58         p[i].f = i;
 59         p[i].r = 0;
 60     }
 61     
 62     for (int i = 0; i < m; ++ i){
 63         if (an[i] == x || bn[i] == x) continue;
 64         
 65         int t1 = find(an[i]), t2 = find(bn[i]);
 66         if (t1 != t2)
 67             merge(an[i], bn[i], xn[i], t1, t2);
 68         if (t1 == t2)
 69             if (!ok(an[i], bn[i], xn[i])){
 70                 line = max(line, i + 1);
 71                 return 0;
 72             }
 73     }
 74     return 1;
 75 }
 76 
 77 int main()
 78 {
 79     while (scanf ("%d%d", &n, &m) != EOF){
 80         if (!m){
 81             if (n == 1) printf ("Player 0 can be determined to be the judge after 0 lines\n");
 82             else printf ("Can not determine\n");
 83             continue;
 84         }
 85 
 86         for (int i = 0; i < m; ++ i)
 87             scanf ("%d%c%d", &an[i], &xn[i], &bn[i]);
 88         
 89         ans.clear();
 90         line = 0;
 91         for (int i = 0; i < n; ++ i)
 92             if (gao(i)) ans.PB (i);
 93 
 94         int sz = ans.size();
 95         if (sz > 1) printf ("Can not determine\n");
 96         else if (!sz) printf ("Impossible\n");
 97         else printf ("Player %d can be determined to be the judge after %d lines\n", ans[0], line);
 98     }
 99     return 0;
100 }
View Code

 

转载于:https://www.cnblogs.com/plumrain/p/POJ_2912.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值