【问题描述】
格斗俱乐部是格斗爱好者的一个组织,在这里,格斗者们能通过与别的成员进行格斗来释放自己的压力与轻松自己的情绪。最近俱乐部举行了一场比赛,该比赛有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”表示不可能。
【输入输出样例1】
data.in
3
0 1 1
0 0 1
0 0 0
data.out
1
0
0
区间dp嘛,状态转移也好想,设 f[ i ][ j ][ k ]表示第 i 个人到第 j 个人打完时第 k 个人能不能活着。所以:枚举中间节点 l ,对于每个 f[ i ][ l ]中可以打赢的那位 x,都和每个 f[ l+1 ][ j ]中可以打赢的那位 y 决一死战,f[ i ][ j ][ winner ]=1。
比较麻烦、比较坑我的地方就是断环为链的操作。见code吧。
但我程序跑得很慢,五重循环,林神好像有很玄学的做法。
先丢个题解链接,日后再看:https://blog.csdn.net/Algor_pro_king_John/article/details/69249109
int n;
int f[100][100][100];
int res[100][100];
int ans[100];
void init()
{
memset(res,0,sizeof(res));
read(n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
read(res[i][j]),res[i][j+n]=res[i+n][j]=res[i+n][j+n]=res[i][j];
//这里决定了我的中心思想是:管他娘的,就当我们有2*n个点,坚持这一指导思想,就可以放心地随便搞了。
}
void work_dp()
{
memset(f,0,sizeof(f));
for(int i=1;i<=(n<<1);++i) f[i][i][i]=1;//显然,初始化。
for(int k=2;k<=n;++k)
for(int i=1;i<=(n<<1)-k+1;++i)//根据上述思想,这是显然的。
{
int j=i+k-1;
for(int l=i;l<=j;++l)
for(int p=1;p<=n<<1;++p)//找活着的f[i][l]。
if(f[i][l][p])
for(int q=1;q<=n<<1;++q)
if(f[l+1][j][q])//找活着的f[l+1][j]。
{
int win_;
if(res[p][q]) win_=p;else win_=q;
f[i][j][win_]=1;
}
}
for(int j=1;j<=n;++j)
for(int i=1;i<=n;++i)
ans[i]|=f[j][j+n-1][i]; //贯彻中心思想,原本还|f[j][j+n-1][i+n]来着,删了也能过,仔细想想是一样的嘛。
for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
}
碰到环的,呃,多笔算一下吧。……