spoj 196 Musketeers(决斗)

黑书中一道例题:决斗https://www.spoj.pl/problems/MUSKET/

书中的分析:

假设需要判断x是否能赢得整场战斗,把环看成链,x点拆成两个,那么编号为x的人能从中胜出的充分必要

条件是他能与自己“相遇”。这样,在连续几个人的链中,只须考虑头尾两个人能否胜利会师,中间的则不予

考虑。设meet[i][j]记录i和j能相遇,能则为true,否则为false,则问题转化为了是否能找到一个k,使得

i 和 k, k和j均能相遇,而 i或j能打败k。

//3463926  	2010-04-04 16:10:26 	superbin	Musketeers	 accepted 	0.03 	 2.7M 	

//技巧将meet加倍,以表示循环的人链

#include <stdio.h>

#include <string.h>

#define NL 110



bool e[NL][NL];

bool meet[NL*2][NL*2];

bool muk[NL];



int main()

{

	int T;

	int n, sum;

	int i, j, k, t;

	char s[NL];

	scanf("%d", &T);

	while (T--) {

		scanf("%d", &n);

		for (i=0; i<n; i++) {

			scanf("%s", s);

			for (j=0; j<n; j++)

				if (s[j]=='1') e[i][j] = 1;

				else e[i][j] = 0;

		}

		memset(muk, 0, sizeof(muk));

		memset(meet, 0, sizeof(meet));				

		for (i=0; i<2*n-1; i++)

			meet[i][i+1] = 1;

		sum = 0;

		for (k=2; k<=n; k++) {

			for (i=0; i+k<2*n; i++) {

				j = i+k;

				int flg = 0;

				for (t=i+1; t<j; t++) {

					if (meet[i][t] && meet[t][j]

						&& (e[i%n][t%n] || e[j%n][t%n])) {

						flg = 1;

						break;

					}

				}

				if (flg) {

					meet[i][j] = 1;

					if (k==n) {

						sum++;

						muk[i] = 1;

					}

				}								

			}

		}

		printf("%d\n", sum);

		for (i=0; i<n; i++) {

			if (muk[i])

				printf("%d\n", i+1);

		}

	}

	return 0;					

}


 

你可能感兴趣的:(poj)