POJ2425 A Chess Game(SG函数+记忆化深搜)
题目链接:传送门
题目大意:
在一个有N个点的拓扑图上(拓扑图以邻接表的形式输入),放M个棋子(棋子与棋子之间无关,可以重合)。
两人轮流移动棋子,每次只能移动一个棋子经过一条边。
问先手是否必胜。
思路:
因为图是确定的,而且是拓扑图,直接沿着边跑记忆化dfs求每个点的SG值就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <set> using namespace std; const int MAX_N = 1005; int N, M; int Edge[MAX_N][MAX_N]; int SG[MAX_N]; int dfs(int u) { if (SG[u] >= 0) return SG[u]; bool vis[MAX_N]; memset(vis, false, sizeof vis); for (int i = 1; i <= Edge[u][0]; i++) { int v = Edge[u][i]; int x = dfs(v); vis[x] = true; } int g = 0; while (vis[g]) g++; return SG[u] = g; } int main() { while (~scanf("%d", &N)) { for (int i = 0; i < N; i++) { SG[i] = -1; scanf("%d", &Edge[i][0]); for (int j = 1; j <= Edge[i][0]; j++) { scanf("%d", &Edge[i][j]); } } for (int i = 0; i < N; i++) dfs(i); while (~scanf("%d", &M)) { if (M == 0) break; int ans = 0; while (M--) { int cur; scanf("%d", &cur); ans ^= SG[cur]; } if (ans) puts("WIN"); else puts("LOSE"); } } return 0; }