ACWing 258 石头剪子布

题意简述

现在有\(n\)个小朋友,已经分成了三份(你并不知道是怎么分的)和一个裁判,每个组里的小朋友都只能出单一的“石头”,或“剪刀”,或“布”,而裁判可以任意出。现在给你\(m\)个对局情况,求出那个裁判。若裁判人选有多个,则输出Can not determine,若必须没有裁判或多余两个裁判,输出Impossible,否则输出裁判和最早能判断裁判的轮数

简单口胡

很容易想到扩展域并查集,将每个小朋友分成三个,一个是他本身(itself),一个是他赢了的(win),一个是他输了的(lose),维护三个并查集,根据\(m\)个对局情况分类讨论维护。
定义如下:

胜负(<,=,>) \(opt\)
< 0
= 1
> 2
集合 对应标号
\(itself_x\) \(x\)
\(win_x\) \(x + n\)
\(lose_x\) \(x + 2n\)
int Go_solve(int _f,bool optx = 1)
{
    bool flag = 1;
    for(int i = 1; i <= 3 * n; i++) f[i] = i;
    for(int i = 1; i <= m; i++)
    {
        if(a[i].x == _f || a[i].y == _f && optx) continue;
        if(a[i].opt == 0) // x < y
        {
            if(find(a[i].x) == find(a[i].y) || find(a[i].x + n) == find(a[i].y)) 
            {
                if(optx == 1) lst[_f] = i;
                if(optx == 0 && (a[i].x == _f || a[i].y == _f)) return i;
                else {flag = 0;break;}
            }
            f[find(a[i].x)] = find(a[i].y + n);
            f[find(a[i].x + n)] = find(a[i].y + 2 * n);
            f[find(a[i].x + 2 * n)] = find(a[i].y);
        }
        else if(a[i].opt == 1)
        {
            if(find(a[i].x + n) == find(a[i].y) || find(a[i].x + 2 * n) == find(a[i].y)) 
            {
                if(optx == 1) lst[_f] = i;
                if(optx == 0 && (a[i].x == _f || a[i].y == _f)) return i;
                else {flag = 0;break;}
            }
            f[find(a[i].x)] = find(a[i].y);
            f[find(a[i].x + n)] = find(a[i].y + n);
            f[find(a[i].x + 2 * n)] = find(a[i].y + 2 * n);
        }
        else if(a[i].opt == 2)
        {
            if(find(a[i].x) == find(a[i].y) || find(a[i].x + 2 * n) == find(a[i].y))  
            {
                if(optx == 1) lst[_f] = i;
                if(optx == 0 && (a[i].x == _f || a[i].y == _f)) return i;
                else {flag = 0;break;}
            }
            f[find(a[i].x)] = find(a[i].y + 2 * n);
            f[find(a[i].x + n)] = find(a[i].y);
            f[find(a[i].x + 2 * n)] = find(a[i].y + n);
        }
    }
    if(optx == 0) return m;
    return flag;
}

并进行处理。
对于求解最早知道是裁判的轮数,可以转变为“将别的不是裁判的都排除掉”,记录下对于每个\(i\)的情况的最早的出现情况的数\(lst_i\),并取最大值。

# include <bits/stdc++.h>
using namespace std;

const int N = 505,M = 2005;

int n,m;

struct node
{
    int x,y,opt;
}a[M];

int f[N * 3];

int find(int x)
{
    if(x != f[x]) f[x] = find(f[x]);
    return f[x];
}

int lst[N];

int Go_solve(int _f,bool optx = 1)
{
    bool flag = 1;
    for(int i = 1; i <= 3 * n; i++) f[i] = i;
    for(int i = 1; i <= m; i++)
    {
        if(a[i].x == _f || a[i].y == _f && optx) continue;
        if(a[i].opt == 0) // x < y
        {
            if(find(a[i].x) == find(a[i].y) || find(a[i].x + n) == find(a[i].y)) 
            {
                if(optx == 1) lst[_f] = i;
                if(optx == 0 && (a[i].x == _f || a[i].y == _f)) return i;
                else {flag = 0;break;}
            }
            f[find(a[i].x)] = find(a[i].y + n);
            f[find(a[i].x + n)] = find(a[i].y + 2 * n);
            f[find(a[i].x + 2 * n)] = find(a[i].y);
        }
        else if(a[i].opt == 1)
        {
            if(find(a[i].x + n) == find(a[i].y) || find(a[i].x + 2 * n) == find(a[i].y)) 
            {
                if(optx == 1) lst[_f] = i;
                if(optx == 0 && (a[i].x == _f || a[i].y == _f)) return i;
                else {flag = 0;break;}
            }
            f[find(a[i].x)] = find(a[i].y);
            f[find(a[i].x + n)] = find(a[i].y + n);
            f[find(a[i].x + 2 * n)] = find(a[i].y + 2 * n);
        }
        else if(a[i].opt == 2)
        {
            if(find(a[i].x) == find(a[i].y) || find(a[i].x + 2 * n) == find(a[i].y))  
            {
                if(optx == 1) lst[_f] = i;
                if(optx == 0 && (a[i].x == _f || a[i].y == _f)) return i;
                else {flag = 0;break;}
            }
            f[find(a[i].x)] = find(a[i].y + 2 * n);
            f[find(a[i].x + n)] = find(a[i].y);
            f[find(a[i].x + 2 * n)] = find(a[i].y + n);
        }
    }
    if(optx == 0) return m;
    return flag;
}

int main(void)
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i = 1; i <= m; i++)
        {
            int ax = 0,bx = 0;
            int k = 0;
            char s[10];
            scanf("%s",s);
            while(isdigit(s[k]))
            {
                ax = ax * 10 + s[k] - '0';
                ++k;
            }
            if(s[k] == '<') a[i].opt = 0;
            else if(s[k] == '=') a[i].opt = 1;
            else if(s[k] == '>') a[i].opt = 2;
            ++k;
            while(isdigit(s[k]))
            {
                bx = bx * 10 + s[k] - '0';
                ++k;
            }
            a[i].x = ax + 1,a[i].y = bx + 1;
        }
        for(int i = 1; i <= 3 * n; i++)
        {
            f[i] = i;        
        }
        /*
        x           itself
        x + n       win
        x + 2 * n   lose
        */
        vector <int> A;
        for(int i = 1; i <= n; i++) lst[i] = 0;
        for(int i = 1; i <= n; i++) // 裁判
        {
            if(Go_solve(i)) 
            {
                A.push_back(i);
            }
        }
        if(A.size() == 0) 
        {
            printf("Impossible\n");
        }
        else 
        {
            if(A.size() >= 2)
            {
                printf("Can not determine\n");
            }
            else
            {
                int cur = 0;
                for(int i = 1; i <= n; i++)
                {
                    cur = max(cur,lst[i]);
                }
                printf("Player %d can be determined to be the judge after %d lines\n",A[0] - 1,cur);
            }
        }
    }
    
    return 0;
}
posted @ 2021-04-27 23:47  luyiming123  阅读(51)  评论(0编辑  收藏  举报