UVa 751 - Triangle War

contents

  1. 1. Problem
  2. 2. Sample Input
  3. 3. Sample Output
  4. 4. Solution

Problem

兩名玩家進行放邊的操作,當其中一名玩家成功創建一個三角形,則可以再放入一邊,直到該操作無法創建一個新的三角形,則進行輪替。最大化自己與對方的分數差異。

一開始先模擬兩名玩家的操作過程。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
4
6
2 4
4 5
5 9
3 6
2 5
3 5
7
2 4
4 5
5 9
3 6
2 5
3 5
7 8
6
1 2
2 3
1 3
2 4
2 5
4 5
10
1 2
2 5
3 6
5 8
4 7
6 10
2 4
4 5
4 8
7 8

Sample Output

1
2
3
4
Game 1: B wins.
Game 2: A wins.
Game 3: A wins.
Game 4: B wins.

Solution

這題很妙,總之先定義狀態 dp(盤面狀況,剩餘三角形) = 最大化差異

那麼轉移方程要看操作是否造成輪替,如果仍然為自己,則把下一步的最大化結果累加上來,反之扣除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <stdio.h>
#include <string.h>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
int dp[1<<18][11];
char used[1<<18][11] = {};
int trans[11][11], tri[10];
int countTri(int state) {
int ret = 0;
for (int i = 0; i < 9; i++) {
if ((state&tri[i]) == tri[i])
ret++;
}
return ret;
}
int dfs(int state, int score) {
if (used[state][score]) return dp[state][score];
used[state][score] = 1;
int ret = 0, nstate, had = 9 - score, c, t;
for (int i = 0; i < 18; i++) {
if ((state>>i)&1) {
nstate = state ^ (1<<i); // used it.
c = countTri(((1<<18)-1)^nstate);
if (c > had) { // create new
t = c - had + dfs(nstate, score - (c - had));
ret = max(ret, t);
} else {
t = score - dfs(nstate, score);
ret = max(ret, t);
}
}
}
dp[state][score] = ret;
return ret;
}
int main() {
// freopen("in.txt", "r+t", stdin);
// freopen("out.txt", "w+t", stdout);
trans[1][2] = 0, trans[1][3] = 1;
trans[2][3] = 2;
trans[2][4] = 3, trans[2][5] = 4, trans[3][5] = 5, trans[3][6] = 6;
trans[4][5] = 7, trans[5][6] = 8;
trans[4][7] = 9, trans[4][8] = 10, trans[5][8] = 11, trans[5][9] = 12, trans[6][9] = 13, trans[6][10] = 14;
trans[7][8] = 15, trans[8][9] = 16, trans[9][10] = 17;
tri[0] = (1<<0)|(1<<1)|(1<<2);
tri[1] = (1<<3)|(1<<4)|(1<<7);
tri[2] = (1<<2)|(1<<4)|(1<<5);
tri[3] = (1<<5)|(1<<6)|(1<<8);
tri[4] = (1<<9)|(1<<10)|(1<<15);
tri[5] = (1<<7)|(1<<10)|(1<<11);
tri[6] = (1<<11)|(1<<12)|(1<<16);
tri[7] = (1<<8)|(1<<12)|(1<<13);
tri[8] = (1<<13)|(1<<14)|(1<<17);
int testcase, cases = 0;
int n, x, y;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d", &n);
int state = 0, A = 0, B = 0, turn = 0;
for (int i = 0; i < n; i++) {
scanf("%d %d", &x, &y);
if (x > y) swap(x, y);
int c = countTri(state|(1<<trans[x][y])) - countTri(state);
if (c) {
if (turn == 0) A += c;
else B += c;
} else {
turn = !turn;
}
state |= 1<<trans[x][y];
}
// printf("score %d %d\n", A, B);
state = ((1<<18)-1)^state; // unused: 1
int had = A + B;
int mx = dfs(state, 9 - had);
if (turn == 0) A += mx, B += 9 - had - mx;
else B += mx, A += 9 - had - mx;
printf("Game %d: %s wins.\n", ++cases, A > B ? "A" : "B");
}
return 0;
}
/*
4
6
2 4
4 5
5 9
3 6
2 5
3 5
7
2 4
4 5
5 9
3 6
2 5
3 5
7 8
6
1 2
2 3
1 3
2 4
2 5
4 5
10
1 2
2 5
3 6
5 8
4 7
6 10
2 4
4 5
4 8
7 8
*/