题目描述:
格斗俱乐部是格斗爱好者的一个组织,在这里,格斗者们能通过与别的成员进行格斗来释放自己的压力与轻松自己的情绪。最近俱乐部举行了一场比赛,该比赛有N位选手参加,他们将围成一个圆圈,每一场比赛圈内任意的两位相邻的选手均可进行相互的格斗,胜利者将留在圈内进入下轮比赛而失败者则直接被送往医院(没有平局)。比赛是残酷的,最后圈内将只剩下一位选手,他将是总冠军。
我们做个奇怪的假设,两位选手进行格斗,他们比赛的结果总是确定的。虽然俱乐部的成员们都很喜欢格斗,但是他们仍然很希望能获得总冠军。现在你通过统计已经知道了任意两位选手格斗的结果,你有责任告诉每位选手,如果赛程合适安排的话,他是否可能成为总冠军。
输入:
数据第一行是一个整数N,(1<=N<=40),表示比赛的选手数量。
接下来给出一个N*N的“0”、“1”矩阵A(行内用空格隔开),第i行第j列为 1表示选手i能战胜选手j,否则选手j能战胜选手i。
你可以假定Aij与Aji(i≠j)均是不同的且Aii=0。比赛开始时所有选手按顺时针方向由编号1到编号N站成一个圈,初始时编号1与编号N的选手是相邻的。
输出:
输出包含N行,每行为一个整数“0”或“1”,“1”表示第i号选手有可能成为冠军,“0”表示不可能。
样例输入: | 样例输出: |
3 0 1 1 0 0 1 0 0 0 | 1 0 0 |
思路:
在做这道题的时候想到要去环,但没有想到用区间DP的方法去实现(有点菜)。
刚开始想用图论遍历的方法来做,通过1~n个点中的任意一个能否遍历到其他的点,能就输出1,不能就输出0,
但题目中的条件是相邻的两人进行格斗,所以这个想法就无疾而终。
用长度2倍的数组去环,再进行区间DP。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=55;
int n;
int a[maxn*2][maxn*2];//两倍的数组(解决环)
int f[maxn*2][maxn*2];//f[i][j]表示第i个人或第j个人能把i+1~j-1的人打败
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
a[i][j+n]=a[i][j];//将环转换成长度为2倍的数组,并转移输赢关系
a[i+n][j]=a[i][j];
a[i+n][j+n]=a[i][j];
}
}
void work()
{
for(int i=1;i<=2*n;i++)
f[i][i+1]=true;//初值
for(int i=2*n-2;i>=1;i--)
for(int j=i+2;j<=2*n;j++)//保证i<j
for(int k=i+1;k<=j-1;k++)
if((i<k) &&(k<j) &&(a[i][k]==1 ||a[j][k]==1) &&(f[i][k]==true) &&(f[k][j]==true))
//k是中间点,位于i和j之间,两端的i和j能打败k,i或k能打败i和k之间的人,j或k能打败j和k之间的人,
//那么i或j就能打败i和j之间的人
f[i][j]=true;
}
int main()
{
init();
work();
for(int i=1;i<=n;i++)
{
if(f[i][i+n]==true) cout<<'1'<<endl;//n个人都被打败
else cout<<'0'<<endl;
}
return 0;
}