决斗 dp, spoj196 Musketeers

题目来源: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;
}



 


 

你可能感兴趣的:(决斗 dp, spoj196 Musketeers)