1. 程式人生 > 實用技巧 >移棋子游戲

移棋子游戲

題目描述

給定一個有N個節點的有向無環圖,圖中某些節點上有棋子,兩名玩家交替移動棋子。
玩家每一步可將任意一顆棋子沿一條有向邊移動到另一個點,無法移動者輸掉遊戲。
對於給定的圖和棋子初始位置,雙方都會採取最優的行動,詢問先手必勝還是先手必敗。

輸入描述:

第一行,三個整數N,M,K,N表示圖中節點總數,M表示圖中邊的條數,K表示棋子的個數。
接下來M行,每行兩個整數X,Y表示有一條邊從X出發指向Y。
接下來一行,K個空格間隔的整數,表示初始時,棋子所在的節點編號。

輸出描述:

若先手勝,輸出win,否則輸出lose。

輸入

6 8 4
2 1
2 4
1 4
1 5
4 5
1 3
3 5
3 6
1 2 4 6

輸出

win

備註:

對於全部資料,N \leq 2000,M \leq 6000,1 \leq K \leq NN2000,M6000,1KN。
// SG函式模板題
#include<bits/stdc++.h>
using namespace std;
const int MAXM = 1e4 + 7;
const int MAXN = 2e3 + 7;
int head[MAXM], ver[MAXM], nex[MAXM], vis[MAXM], sg[MAXM], tot;
int N, M, K;
void add(int x, int y) {
    ver[
++tot] = y; nex[tot] = head[x]; head[x] = tot; } void dfs(int x) { if (vis[x]) return; vis[x] = 1; int up = 0; int mark[MAXN] = {0}; for (int i = head[x]; i; i = nex[i]) { dfs(ver[i]); up = max(up, sg[ver[i]]); mark[sg[ver[i]]] = 1; } for (int i = 0; i <= up + 1
; i++) { if (!mark[i]) { sg[x] = i; break; } } } void getSG() { for (int i = 1; i <= N; i++) { if (!vis[i]) dfs(i); } } int main() { int x, y; cin >> N >> M >> K; for (int i = 1; i <= M; i++) { cin >> x >> y; add(x, y); } getSG(); int ans = 0; for (int i = 1; i <= K; i++) { cin >> x; ans ^= sg[x]; } if (ans) cout << "win" << endl; else cout << "lose" << endl; return 0; }