HRBUST 1162 魔女【DP】

Description

平行世界是动漫作品中经常涉及的题材,而且往往这些作品都相当的精彩,如《寒蝉鸣泣之时》、《CLANNAD》、《魔法少女小圆》、《命运石之门》等。世界从诞生到结束,最终又轮回到诞生。无论命运如何的绝对,在无数次的轮回中终将被打破,犹如掷骰子,在无限接近于零但不等于零的机率中往复。这样在无限的反复和轮回中,将其可能性放大到100%。最典型的人物就是《海猫鸣泣之时》中的能无限次引发奇迹力量的“奇迹之魔女”贝伦卡斯泰露。而与此对应的是能够让事件发生的可能性无限接近于零“绝对的魔女”拉姆达戴露塔。在故事中,贝伦的目的是为了令主角战人在黄金魔女的游戏中“赢”,而拉姆达的目的则是为了让游戏永远“平局”下去。
由于可以无限的轮回,因此可以将整个黄金魔女的游戏看成一个环,在游戏中有n个关键人物。人物之间存在着胜败关系,如果两个人之间发生斗争,实力强的一方会获胜,而实力弱的一方会被击败退出游戏。一开始每个人物只会跟编号排在他后面的人接触,比如人物1会跟人物2之间斗争,人物2会跟人物3斗争,人物n会跟人物1斗争。当人物消失后,胜者就会接触到下一个人物,比如人物1战胜了人物2,人物2退出了游戏,那它就会跟人物3之间产生斗争。各个人物之间的胜败情况是固定的。最终游戏中只会剩下一个人,成为游戏最终的胜者。但是人物不同的战斗顺序,最终胜利的这个人可能不同。
现在的问题是,在这场“黄金的魔女”设下的棋局中,“绝对的魔女”使得人物与人物的胜败关系是确定的,而“奇迹的魔女”想知道,这场游戏中,都有哪些人是有可能生存下来的。

Input

有多组数据,第一行是一个整数n表示事件的数目。(2<=n<=100)
随后的n行是一个n行n列的矩阵。矩阵中的第i行第j列,如果为1,表示人物i与人物j斗争时人物i会胜利。为0则表示,表示人物i与人物j斗争时人物j会胜利。

Output

对于每组测试数据,第一行输出一个k表示有多少个人物可能获胜,接下来的k行每行输出一个人物的编号,编号从小到大输出。

Sample Input

3
0 1 0
0 0 1
1 0 0

2
0 0
1 0
Sample Output

3
1
2
3
1
2

 

思路:和lrj的例题决斗思路一样,meet[i,j]表示是否有可能i和j相遇, 则第i个人能取得最后的胜利当且仅当meet[i,i]为true.如果i最后能碰到自己,即她能存留下来

状态转移: 考虑相遇前的最后一步, 则meet[I,j]为true当且仅当–能找到一个k, 使得i能遇k, k能遇到j, 且i或者j能打败k.
代码如下:

#include<stdio.h>
#include<string.h>
int meet[103][103], d[103][103];
int main()
{
int n, i, t, j, k, mm;
while(scanf("%d", &n)!=EOF)
{
memset(d, 0, sizeof(d));
memset(meet, 0, sizeof(meet));
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
scanf("%d", &mm);
if(mm==1)
d[i][j]=1;
}
}
for(i=0; i<n-1; i++)
meet[i][i+1]=1, meet[i+1][i]=1;
meet[0][n-1]=1, meet[n-1][0]=1;
int flag;
for(t=2; t<=n; t++)
for(i=0;i<n;i++)
{
j=(i+t)%n;
flag=0;
for(k=(i+1)%n; k!=j; k=(k+1)%n)
{
if(meet[i][k]&&meet[k][j]&&(1==d[i][k]||1==d[j][k]))
{
meet[i][j]=1;
flag=1;
break;
}
}
if(!flag)
meet[i][j]=0;
}
int num=0;
for(i=0; i<n; i++)
if(meet[i][i])
num++;
printf("%d\n", num);
for(i=0; i<n; i++)
if(meet[i][i])
printf("%d\n", i+1);
}
return 0;
}

 
原文地址:https://www.cnblogs.com/Hilda/p/2616789.html