1. 程式人生 > >A Chess Game POJ - 2425(SG函式)

A Chess Game POJ - 2425(SG函式)

POJ 2425
題意:
一個有向無環圖,在若干點上有若干棋子,兩人輪流移動棋子,每次只能將一個棋子移動一步,當無棋子可移動時輸,即移動最後一枚棋子者勝;
思路:
假設只有一枚棋子,那麼對於一個點的勝負局面其實就是其SG值;
多枚棋子的勝負局面就是每個點的SG值異或和;
現在就是要求每個點的SG值;
SG(x)=mex(SG(y) | y是x的後繼點);
mex(minimal excludant)定義:這是施加於一個集合的運算,表示最小的不屬於這個集合的非負整數。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0;
SG的求解可以直接暴力求解,也可以dfs記憶化搜尋;
此題直接搜尋會超時;

#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
vector<int> vec[1010];
int sg[1010], n;
//DFS求解SG函式;
int SG(int x){
	int vis[1010];
	if(sg[x]!=-1) return sg[x];
	memset(vis, 0, sizeof(vis));
	for(int i=0; i<vec[x].size(); i++){
		vis[SG(vec[x][i])]=1;
	}
	for(int i=0; i<n; i++) 
		if(!vis[i]) return sg[x]=i;
}
int main(){
	while(~scanf("%d", &n)){
		for(int i=0; i<n; i++) vec[i].clear();
		int m, p;	
		memset(sg, -1, sizeof(sg));
		for(int i=0; i<n; i++){
			scanf("%d", &m);
			for(int j=0; j<m; j++){
				scanf("%d", &p);
				vec[i].push_back(p);
			}
			if(m==0) sg[i]=0;
		}
		for(int i=0; i<n; i++){
			if(sg[i]==-1) sg[i]=SG(i);
		}
//		for(int i=0; i<n; i++){
//			printf("%d:  %d\n", i, sg[i]);
//		}
		while(scanf("%d", &m), m){
			int pos, ans=0;
			for(int i=0; i<m; i++){
				scanf("%d", &pos);
				ans^=sg[pos];
			}
			if(ans) printf("WIN\n");
			else printf("LOSE\n");
		}
	}
	return 0;
}