2.圆桌游戏

【问题描述】

一种圆桌游戏这样进行的:n个人围着圆桌一圈,按顺时针顺序依次标号1n号。1<i<ni来说,i的左边i+1号,右边是i-1号1的右边是n号n号的左边是1每一轮游戏时,主持人指定一个还在桌边的人(假设i号),让他向坐在他边的人(假设j号)发起挑战,如果挑战成功,那么j离开圆桌,如果挑战失败,那么i离开圆桌。当圆桌边只剩下一个人时,这个人是最终的胜利者。

事实上,胜利者的归属是与主持人的选择息息相关现在,你来担任圆桌游戏的主持人并且你已经事先知道了对于任意两个人i号和j号,如果ij发起挑战结果是成功还是失败。现在你想知道,如果可以随意指定每轮发起挑战的人,哪些人成为最终的胜利者? 

【输入】

第一行包含一个整数n,表示参加游戏的人数

接下来n每行包含n个数,每个数都是01的一个,若第i行第j数是1表示ij发起挑战的结果是成功,否则表示挑战结果是失败。第i第i列的值一定为0 

【输出】

一行包含若干个表示可能成为最终胜利者玩家的标号。标号按从小到大的顺序输出,相邻两个数1空格隔开。 

【输入输出样例1】

game.in

game.out

3

0 1 0

0 0 1

0 1 0

1 3

见选手目录下的game / game1.in与game / game1.out 

【输入输出样例1说明】

先指定2号向3发起挑战,3离开;再指定1号向2号发起挑战,2号离开。此时1最终胜利者

指定1号向2号发起挑战,2号离开;再指定1号向3号发起挑战,1号离开。此时3是最终胜利者。

无论如何安排挑战顺序,2都无法成为最终胜利者。 

【输入输出样例2】

见选手目录下的game / game2.in与game / game2.out 

【数据规模与约定】

对于30%的数据,n≤7

对于100%的数据,n≤100

 

暴力30;

  搜索,二进制模拟状态,每次枚举对战的两方,直到只剩一人。

  

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000010
#define ll long long
using namespace std;
int n;
int on[120][120];
bool ok[110];
inline void dfs(int line)
{
//    printf("%d ",line);
    int o=1;
    for(int i=1,j=1;i<=n;i++,o<<=1)
    {
        if((line&o)==o)
        {
            if(line-o>o)
            {
                int oo=o*2;
                for( j=i+1;j<=n;j++,oo<<=1)
                    if((line&oo)==oo) break;
                if(on[i][j])    dfs(line-oo);
                else dfs(line-o);    
            }else
            {
                int oo=1;
                for(j=1;j<=i;j++,oo<<=1)
                    if((line&oo)==oo)    break;
                //    printf("\n") ;
                if(j<i)    
                {
                    if(on[i][j])    dfs(line-oo);
                    else dfs(line-o);
                }
                else if(i==j)
                {
                    ok[i]=1;
                }
            }            
        }
    }
    return ; 
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)    
        scanf("%d",&on[i][j]);
        

    dfs((1<<n )-1);
    
    for(int i=1;i<=n;i++)
        if(ok[i])    printf("%d ",i);
    return 0;
} 
30分代码

满分做法:  区间dp

  记f[i][j]为i和j两个人会相连,如果f[i][i+n]相连,则i可能是最终胜利者。

  预处理,因为是个环我们用两倍的链来记,

      f[i][i+1]一定会相连。

  转移:

    如果i,k,j能连接,且(i能打赢k 或 k挑战 j 失败) i和j就能连接。 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000010
#define ll long long
using namespace std;
int n;
bool on[120][120];
bool f[210][210];
int s[210];
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)    
        scanf("%d",&on[i][j]);
    
    for(int i=1;i<=n;i++)
        s[i]=s[i+n]=i;
    for(int i=1;i<=n+n-1;i++)    f[i][i+1]=1;
    for(int i=n+n-2;i>=1;i--)
    for(int j=i+2;j<=n+n;j++)
    for(int k=i+1;k<j;k++)
    if(f[i][k]&&f[k][j]&&(on[s[i]][s[k]]||!on[s[k]][s[j]]) )
    {
        f[i][j]=1;
        break;
    }
    for(int i=1;i<=n;i++)
    if(f[i][i+n])    printf("%d ",i);
    return 0;
} 
100

小样例:

输入 3

  1 1 1

  1 1 1

  1 1 1

输出 1 2 3

posted @ 2017-09-13 17:50  浪矢-CL  阅读(810)  评论(0编辑  收藏  举报