题目来源:6th Polish Olympiad in Informatics, stage 1
题目连接:http://www.spoj.pl/problems/MUSKET/(找了很久才找到的,这成了我在spoj上的第一道题)
黑书上的例题 p117页
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
const int M = 105;
char f[M][M];
int dp[M][M];
int s[M]; //把人存成链式的
int meet(int a, int b)
{
if(dp[a][b] != -1) return dp[a][b]; //如果dp[a][b]搜索过了,则直接返回
if(b == a+1) //如果两个人相邻,直接返回1
return 1;
int flag = 0;
for(int i = a+1; i < b; i++)
{
//如果在s[a]和s[b]之间存在一个人会输给s[a]或者s[b],递归将人链分成两段
if((f[s[a]][s[i]] == '1' || f[s[b]][s[i]] == '1') && meet(a, i) && meet(i, b))
{
flag = 1;
break;
}
}
return dp[a][b] = flag; //记忆化搜索
}
int main()
{
int cas, n, i, j, ans[M], cnt;
scanf("%d", &cas);
while(cas--)
{
scanf("%d", &n);
getchar();
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
scanf("%c", &f[i][j]); // 字符读入, 因为我从j = 1开始读入,就没用字符串一行一行读入
getchar();
}
cnt = 0;
for(i = 1; i <= n; i++)
{
memset(dp, -1, sizeof(dp));
int t = i;
for(j = 0; j <= n; j++) //循环n+1次,s[0]和s[n] 都存储的第i个人,就是把第i个人拆成两个点,分别放在链的首位
{
if(t <= n)
s[j] = t;
else
s[j] = t-n;
t++;
}
if(meet(0, n)) //若首尾两点能相遇,则第i个人能胜出
ans[cnt++] = i; //记录第i个人能获胜
}
printf("%d\n", cnt);
for(i = 0; i < cnt; i++)
printf("%d\n", ans[i]);
}
return 0;
}