POJ 3317 - Stake Your Claim
http://poj.org/problem?id=3317
概要
n * n のボード上にプレイヤー0, 1 がプレイヤー0から順に交互に自分の番号を置いていく. ボードが埋まったらゲーム終了で,それぞれ連続したマスの数の最大値がそのプレイヤーの得点となる.
まだ k 個置けるようなボードの状態が与えられる. それぞれのプレイヤーが最良の手を選んでゲームを続けたとき,最初の一手とそのときに最終的に何点差で勝つ(負ける場合は負になる)かを答える.
制約
- n <= 8
- 1 <= k <= 10
解法
ゲーム木探索.
アルファ・ベータ法 - Wikipedia を実装した.
poj/3317.cc1 #include <iostream> 2 #include <vector> 3 #include <queue> 4 using namespace std; 5 6 struct board 7 { 8 vector<pair<int,int> > holes; 9 vector<int> cache; 10 board(vector<string>& g, const vector<pair<int,int> >& h) 11 : holes(h), cache(1<<h.size()) 12 { 13 build_cache(g); 14 } 15 16 void build_cache(vector<string>& grid) 17 { 18 const int N = holes.size(); 19 for (int s = 0; s < (1<<N); s++) { 20 const int x = __builtin_popcount(s); 21 if (N/2 != x && (N+1)/2 != x) { 22 continue; 23 } 24 for (int i = 0; i < N; i++) { 25 grid[holes[i].first][holes[i].second] = s & (1<<i) ? '1' : '0'; 26 } 27 cache[s] = evaluate(grid); 28 } 29 } 30 31 static int evaluate(const vector<string>& grid) 32 { 33 const int H = grid.size(); 34 const int W = grid[0].size(); 35 vector<vector<int> > visited(H, vector<int>(W, false)); 36 int ans[2] = {0, 0}; 37 for (int i = 0; i < H; i++) { 38 for (int j = 0; j < W; j++) { 39 if (visited[i][j]) { 40 continue; 41 } 42 43 const char c = grid[i][j]; 44 visited[i][j] = true; 45 queue<pair<int,int> > q; 46 q.push(make_pair(i, j)); 47 int d = 0; 48 while (!q.empty()) { 49 const int k = q.front().first; 50 const int l = q.front().second; 51 q.pop(); 52 ++d; 53 for (int t = 0; t < 4; t++) { 54 static const int di[] = {-1, 1, 0, 0}; 55 static const int dj[] = {0, 0, -1, 1}; 56 const int x = k + di[t]; 57 const int y = l + dj[t]; 58 if (0 <= x && x < H && 0 <= y && y < W && !visited[x][y] && grid[x][y] == c) { 59 visited[x][y] = true; 60 q.push(make_pair(x, y)); 61 } 62 } 63 } 64 ans[c-'0'] = max(ans[c-'0'], d); 65 } 66 } 67 return ans[0] - ans[1]; 68 } 69 70 pair<int, pair<int,int> > alphabeta(int turn, int alpha = -1000000, int beta = 1000000, int s = 0, int t = 0) const 71 { 72 const int N = holes.size(); 73 if (s == (1<<N)-1) { 74 return make_pair(turn * cache[t], make_pair(-1, -1)); 75 } 76 77 pair<int,int> move(-1, -1); 78 for (int i = 0; i < N; i++) { 79 if (!(s & (1<<i))) { 80 const int x = -alphabeta(-turn, -beta, -alpha, s | (1<<i), t | (turn == 1 ? 0 : (1<<i))).first; 81 if (x > alpha) { 82 alpha = x; 83 move = holes[i]; 84 } 85 if (alpha >= beta) { 86 return make_pair(alpha, move); 87 } 88 } 89 } 90 return make_pair(alpha, move); 91 } 92 }; 93 94 int main() 95 { 96 int N; 97 while (cin >> N && N != 0) { 98 vector<string> grid(N); 99 vector<pair<int,int> > holes; 100 int zero = 0, one = 0; 101 for (int i = 0; i < N; i++) { 102 cin >> grid[i]; 103 for (int j = 0; j < N; j++) { 104 if (grid[i][j] == '.') { 105 holes.push_back(make_pair(i, j)); 106 } else if (grid[i][j] == '0') { 107 ++zero; 108 } else { 109 ++one; 110 } 111 } 112 } 113 114 const board b(grid, holes); 115 const int turn = (N*N - holes.size()) % 2 == 0 ? 1 : -1; 116 const pair<int, pair<int,int> > r = b.alphabeta(turn); 117 cout << "(" << r.second.first << "," << r.second.second << ") " << r.first << endl; 118 } 119 return 0; 120 }