POJ 2912 Rochambeau(枚举+加权并查集)

来源:互联网 发布:excel筛选重复数据函数 编辑:程序博客网 时间:2024/05/01 23:07

题目链接:
POJ 2912 Rochambeau

/*题意:有n个人玩石头剪刀布,有且只有一个裁判。除了裁判每个人的出拳形式都是一样的。a<b表示b打败a,a=b表示a和b出拳一样,平手。a>b表示a打败b。给出m个回合的游戏结果,问能否判断出谁是裁判?如果能还要输出是在哪个回合之后判断出谁是裁判。分析:枚举和加权并查集。对于每个人假设其为裁判,然后去掉所有和他有关的匹配,判断是否会出现矛盾。val[i]=0:i和根节点属于同一集合;val[i]=1:根节点打败i;val[i]=2:i打败根节点在寻找根节点的find()函数中,val的更新函数是:val[x]=(val[x]+val[pre[x]])%3;举个例子:找到根节点之前val[x]=1,val[pre[x]]=2:表示父节点打败x,父节点也打败父节点的父节点。(注意此时val[x]是x与父节点的关系)所以按照递归的思路,从递归倒数第二层开始pre[x]就表示为根节点了,那么pre[x]打败根节点。又因为pre[x]也打败x所以val[x]=0=(1+2)%3;递归在往上一层时pre[x]又表示为根节点了。再来看看合并操作时的val关系。fa,fb分别为aa,bb的根节点,ww是aa与bb的关系。当fa!=fb时,令pre[fa]=fb.假设val[aa]=1,即fa打败aa①,val[bb]=2,即bb打败fb②,ww=1,即bb打败aa③。则由②③的aa和fb是同一集合。再由①得fa打败fb。即val[fa]=2.也就是val[fa]=(val[bb]-val[aa]+ww)%3,但是由于有可能val[bb]-val[aa]+ww<0,所以正确的方程是:val[fa]=(val[bb]-val[aa]+ww+3)%3,当fa==fb时,那么就要判断是否出现矛盾,如果出现矛盾那么说明i不能作为裁判。判断矛盾是:(val[aa]-val[bb]+3)%3和ww是否相等。如果不矛盾,那么就接着读入输入到最后。还要注意一点就是可能会出现多个裁判,那就是Can not determine。*/#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int maxn = 510;const int maxm = 2010;int n,m,aa,bb,ww;int pre[maxn],val[maxn];int line,tmpline, ans,cnt,flag;char s;struct Read {    int a, b, w;}read[maxm];void init(){    for (int i = 0; i <maxn; i++)    {        pre[i] = i;        val[i]=0;    }}int find(int x){    if(pre[x]==x) return x;    int tmp=find(pre[x]);    val[x]=(val[x]+val[pre[x]])%3;    return pre[x]=tmp;}int main(){#ifdef LOCAL    freopen("in.txt", "r", stdin);    //freopen("out.txt","w",stdout);#endif    while (~scanf("%d%d", &n, &m))    {        if (m == 0)        {            //printf("case 1\n");            if(n==1) printf("Player 0 can be determined to be the judge after 0 lines\n");            else printf("Can not determine\n");            continue;        }        for (int i = 0; i<m; i++)        {            scanf("%d%c%d", &aa, &s, &bb);            read[i].a=aa;            read[i].b=bb;            if (s == '=') read[i].w=0;            else if(s=='<') read[i].w=1;            else if(s=='>') read[i].w=2;        }        line=-1;        cnt=0;        for(int i=0;i<n;i++)//枚举每个人        {            init();            tmpline=-1;            flag=0;            for(int j=0;j<m;j++)            {                aa=read[j].a;                bb=read[j].b;                ww=read[j].w;                if(aa==i||bb==i) continue;//去掉i的影响看是否还会出现矛盾                int fa=find(aa);                int fb=find(bb);                if(fa!=fb)                {                    pre[fa]=fb;                    val[fa]=(val[bb]-val[aa]+ww+3)%3;                }                else                {                    if((val[aa]-val[bb]+3)%3!=ww)//出现矛盾                    {                        tmpline=j+1;//出现矛盾所在行                        flag=1;                        break;                    }                }                if(flag) break;            }            if(flag==0)//没出现矛盾            {                ans=i;//i可以是裁判                cnt++;                if(cnt>=2) break;//裁判数量>=2            }            else line=max(line,tmpline);//        }        if(cnt==0)        {            //printf("case 2\n");            printf("Impossible\n");        }        else if(cnt>=2)        {            //printf("case 3\n");            printf("Can not determine\n");        }        else        {            //printf("case 4\n");            printf("Player %d can be determined to be the judge after %d lines\n",ans,line);        }    }    return 0;}
0 0
原创粉丝点击