標籤:style http color os io for ar cti
題目連結:uva 12163 - Addition-Subtraction Game
題目大意:兩個人進行遊戲,對於每一局有一個無向圖,給出無向圖,每個節點有個K值,兩人輪流操作,每次可以選中國一個含有石子的節點,將該節點的一個石子拿掉,然後選擇K個有邊串連的節點加上一個石子(節點可以重複選擇),每個節點的子節點不會超過15個。不能操作的人視為失敗。每局有n輪,給定每輪中每個節點上石子的初始值,問先手勝利還是失敗。
解題思路:有向圖上移動石子的組合遊戲,對於沒有子節點的節點SG值為0,然後對於每個節點,用記憶化的方式處理出SG值,注意因為要選中K個節點,但是子節點的個數最多為15,然後對於選中偶數次的節點可視沒選,所以枚舉215狀態即可,並且要保證選中的個數奇偶性和K值相同。
對於每一輪給定的初始狀態,計算各個子遊戲的Nim和即可。
#include <cstdio>#include <cstring>#include <vector>#include <map>#include <algorithm>using namespace std;const int maxn = 105;vector<int> g[maxn];int N, M, s[maxn], val[maxn];inline int bitcount (int x) { return x == 0 ? x : bitcount(x>>1) + (x&1);}int SG (int x) { if (s[x] != -1) return s[x]; map<int, int> vis; int n = g[x].size(); if (n == 0) return s[x] == 0; for (int i = 0; i < (1<<n); i++) { int bit = bitcount(i); if (bit > val[x] || (bit&1) != (val[x]&1)) continue; int tmp = 0; for (int j = 0; j < n; j++) { if (i&(1<<j)) tmp ^= SG(g[x][j]); } vis[tmp] = 1; } int ret = -1; while (vis.count(++ret)); return s[x] = ret;}void init () { scanf("%d%d", &N, &M); for (int i = 0; i < maxn; i++) g[i].clear(); int u, v; for (int i = 0; i < M; i++) { scanf("%d%d", &u, &v); g[u].push_back(v); } for (int i = 0; i < N; i++) scanf("%d", &val[i]); memset(s, -1, sizeof(s)); for (int i = 0; i < N; i++) s[i] = SG(i);}void solve () { int Q; scanf("%d", &Q); for (int i = 1; i <= Q; i++) { int ret = 0, x; for (int j = 0; j < N; j++) { scanf("%d", &x); if (x&1) ret ^= s[j]; } printf("Round#%d: %s\n", i, ret ? "WINNING" : "LOSING"); } printf("\n");}int main () { int cas; scanf("%d", &cas); for (int k = 1; k <= cas; k++) { init(); printf("Game#%d:\n", k); solve(); } return 0;}