圆桌游戏

【题目描述】

有n个人围着圆桌坐成一圈,按顺时针顺序依次标为1~n号。对于i(1 < i < n)号来说,其左边为i+1号,右边为i-1号,1号右边为n号,n号左边为1号。

每轮游戏会指定一个坐在圆桌边的人(设为i号),使其向左边的人(设为j号)发起挑战,若挑战成功,则j离开圆桌,若挑战失败,则i离开圆桌,当圆桌边只剩下一个人时,则其为最终胜利者。

现已知,对于任意两个人i号、j号,若i向j发起挑战,结果是成功还是失败。假设每轮游戏可以随意指定发起挑战的人,询问哪些人可以成为最终胜利者。

【输入描述】

第一行输入一个整数n,表示参加游戏的人数;

接下来n行,每行输入n个0或1,若第i行第j列为1,则表示i向j发起挑战会成功,否则表示挑战会失败,第i行第i列的值为0。

【输出描述】

输出一行数,表示可能成为最终胜利者的人的标号,标号按从小到大的顺序输出。

【输入样例】

3

0 1 0

0 0 1

0 1 0

【输出样例】

1 3

【数据范围及提示】

样例解释:

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

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

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

对于30%的数据,n ≤ 7;

对于100%的数据,n ≤ 100。

源代码:

#include<cstdio>
int n;
bool i[201][201]={0},f[201][201]={0};
int main() //区间型动态规划(环形)。
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      for (int b=1;b<=n;b++)
      {
          scanf("%d",&i[a][b]);
          i[a][b+n]=i[a+n][b]=i[a+n][b+n]=i[a][b]; //i[][]表示挑战结果。
      }
    for (int a=1;a<(n<<1);a++) //f[][]表示两个人有没有可能相邻。
      f[a][a+1]=true;
    for (int a=(n<<1)-2;a>0;a--) //起点。
      for (int b=a+2;b<=(n<<1);b++) //终点。
        for (int c=a+1;c<b;c++) //中间点。
          if (f[a][c]&&f[c][b]&&(i[a][c]||!i[c][b])) //可能相邻且退出条件满足。
          {
            f[a][b]=true; //有可能相邻,中断。
            break;
          }
    for (int a=1;a<=n;a++)
      if (f[a][a+n]) //自己与自己有可能相邻,则符合题意。
        printf("%d ",a);
    return 0;
}

/*
    循环类似于环形石子合并。
    然后就从小区间枚举起点终点,逐渐扩大,中间点退出有两种情况,前点与其挑战赢,其与后点挑战输。
*/
posted @ 2016-10-17 10:16  前前前世。  阅读(759)  评论(0编辑  收藏  举报