zoukankan      html  css  js  c++  java
  • 【带权并查集+枚举】Rochambeau POJ

    Rochambeau POJ - 2912

    题意:

    (N)个小孩玩(M)轮剪刀石头布。其中(1)个小孩是法官,剩下的小孩分为(3)组(可能有空的组)。每轮游戏随机从所有小孩中抽两个人,同组的小孩会出同样的手势,不同组的小孩会出不同的手势,法官可以随意出手势。现给出(M)轮游戏的结果,问哪个小孩是法官,以及猜出法官所需要的最少结果数。

    思路:

    剪刀石头布之间的输赢关系和食物链那题是一样的,所以公式可以照搬。

    但与做过的带权并查集的题目不同的是,本题不仅要找到矛盾,还得找到谁是矛盾的源头。

    这里用枚举法,假设第(i)个小孩是法官,再看剩下的与(i)无关的关系是否矛盾。因为除了法官之外其它小孩都不能随意出拳,所以与(i)无关的输赢结果都是可推理的。如果不矛盾,则(i)可以是法官;如果有矛盾,(i)一定不是法官。

    • Impossible:所有小孩中没有一个可能是法官

    • Can not determine:所有小孩中有多于一个可能是法官

    • Player (i) can be determined to be the judge after (x) lines:所有小孩中只有一个可能是法官

    在枚举的过程中统计“可以是法官”的人数即可判断出是三种情况中的哪一种。

    至于最少多少行可以确定法官,应当逆向思考:最少多少行可以确定剩下(n-1)个人不是法官。那么可以在枚举的过程中,找出判断某个小孩不是法官所需的最多的行数(cnt)。因为其它小孩都已经在(cnt)行之前就可以确定不是法官了。到第(cnt)行的时候,这(n-1)个小孩都可以确定不是法官。

    因为没意识到我的数组需要存m条关系,把maxn设成了510,WA到怀疑人生……

    期间找了若干题解来看,发现思路都一致,但我的代码还更简洁一些。

    const int maxn = 2000 + 100;
    
    int fa[maxn], rela[maxn];
    int x[maxn], y[maxn], r[maxn];
    
    int find(int x) {
        if (fa[x] == -1) return x;
        int tmp = find(fa[x]);
        //0与父节点平局,1赢了父节点,2输了
        rela[x] = (rela[x] + rela[fa[x]]) % 3;
        return fa[x] = tmp;
    }
    
    bool merge(int x, int y, int rr) {
        int r1 = find(x);
        int r2 = find(y);
        if (r1 == r2) {
            return rr == (rela[x] - rela[y] + 3) % 3;
        }
        else {
            fa[r1] = r2;
            rela[r1] = (rela[y] - rela[x] + rr + 3) % 3;
            return true;
        }
    }
    
    int main()
    {
        //ios::sync_with_stdio(false);
        int n, m;
        while (cin >> n >> m) {
            int judge = 0;
            int cnt = 0;
            int ans = 0;
            for (int i = 1; i <= m; i++) {
                char s;
                cin >> x[i] >> s >> y[i];
                if (s == '<') r[i] = 2;
                else if (s == '>') r[i] = 1;
                else r[i] = 0;
            }
            for (int i = 0; i < n; i++) {
                //先假设小孩i是judge,再以此出发判断与他无关的其它所有关系是否存在矛盾
                int ok = 1;
                for (int i = 0; i <= n; i++) fa[i] = -1;
                memset(rela, 0, sizeof(rela));
                //注意要在这里初始化
                for (int j = 1; j <= m; j++) {
                    int u = x[j], v = y[j], rr = r[j];
                    if (u == i || v == i) continue;
                    //不用判断和judge相关的关系
                    if (!merge(u, v, rr)) {
                        ok = 0;
                        //其它关系出现矛盾,则小孩i不可能是judge
                        cnt = max(j, cnt);
                        //记录一下最多需要多少条关系来排除某个小孩的嫌疑
                        break;
                    }
                }
                if (ok) {
                    ++judge;
                    //统计“可能是法官”的人数
                    ans = i;
                    //记录法官的编号
                    //需要输出ans的时候必然只找到一个法官
                }
            }
            if (judge == 0) cout << "Impossible" << endl;
            else if (judge > 1) cout << "Can not determine" << endl;
            else cout << "Player " << ans << " can be determined to be the judge after " << cnt << " lines" << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    获取JVM的dump文件
    jmeter正则表达式提取器提取特定字符串后的全部内容
    mysql数据库开启慢查询日志
    正则中需要转义的特殊字符
    LoadRunner 调用Dll完成加密解密
    压缩十进制数据的一次实践
    记Judith此人和我对美国教育的感触
    在 sql server 中,不允许用户查看到所有数据库
    在 asp.net core 中使用 HttpContext.Current
    nginx 配置将某站点所有页面指向一个路径
  • 原文地址:https://www.cnblogs.com/streamazure/p/13475529.html
Copyright © 2011-2022 走看看