UVA 11884 A Shooting Game(记忆化搜索)

A and B are playing a shooting game on a battlefield consisting of square-shaped unit blocks. The blocks are occupying some consecutive columns, and the perimeter of the figure equals the perimeter of its minimal bounding box. The figure (a) below is a valid battlefield, but (b) and (c) are not, because in (b), there is an empty column; in (c), the perimeter of figure is 14, but the perimeter of the bounding box (drawn with dashed lines) is 12. With the help of gravity, each block is either located on another block, or sitting on the ground. To make the battlefield look more exciting, it must not be a perfect rectangle (i.e. it is not allowed that every column has the same height)

 

Here is the rule of the game:

  1. A and B shoot by turn. A starts first.
  2. Before shooting, the player first select one row with at least one block, and one of the two directions "left" and "right", then shoot at this row along that direction. The power of the shoot is one of 1, 2 or 3, each with probability of 1/3. The power of shoot is the number of blocks (not necessarily consecutive) that can be destroyed in this shoot. If the total number of blocks on this row is less than the power of shoot, then all the blocks on this row is destroyed. For example, if the player chooses to shoot the 3rd row from the bottom, with direction "right", power 2, and there are 4 blocks on this row, then the left-most two blocks are destroyed.
  3. After each shoot, blocks in the air fall down vertically. The next player cannot shoot before all the blocks stop falling.
  4. Realize that the intermediate battlefields do not have to follow the constraints for starting battlefields. For example, it could happens some situations looking as figures (b) or (c), and then, if the power is p, the leftmost/rightmost p blocks of columns which contain a block in this row are destroyed (skipping empty positions).
  5. He who destroys the last block wins.

Assume the starting battlefield is  . According to rule 1, A shoots first. The table below shows three (not all) possible outcomes of the first shot:

 

Row(from bottom) Direction Power Befrore Falling Stable
2 Left 1 (Same as left)
1 Left 2
1 Right 3

Assume Alice and Bob are both very clever (always follows the strategy that maximizes the probability he/she wins), what is the probability that Alice wins?

Input 

There will be at most 25 test cases, each with two lines. The first line is a single integer n ( 1n6), the number of columns. The second line contains n integers h1h2, ..., hn ( 1hi6), the heights of the columns from left to right. The battlefield is guaranteed to satisfy the restrictions in the problem (perimeter of figure equals that of the minimal bounding box, and is not a perfect rectangle). Input is terminated by n = 0.

Output 

For each test case, print a single line, the probability that A wins, to six decimal points.

 

题目大意:题目好长>_<。大致是说有一个游戏,有n列,每列最多6个方块,这些方块是垂直放的如果下面没有东西了就会垂直掉下来(初始方块的状态有限制条件不过这题没用)。现在有两个人玩游戏,他们各有一支枪,每发子弹的攻击力为1、2或3,概率均为1/3。可以选择从左攻击或从右攻击,可以自己选择一行,发射子弹之后最多打掉子弹攻击力个方块(如果子弹攻击力比方块多,那么就只有浪费掉了),然后悬浮的方块会往下掉。现在这两个人都足够聪明,每次都会选择胜率最高的来开枪,问先手的胜率。

思路:容易看出状态数最多有7^6=117649种,记忆化搜索可以解决(我总觉得这是暴力求破)。分别计算从左边六行发射子弹的胜率,再计算右边六行发射子弹的胜率,取最大的一个(这玩游戏的人真是神智商,你以为个个都是冯洛伊曼吗……)。用dp[x1][x2][x3][x4][x5][x6]来记录一个人面临第一列x1个,第二列x2个……的状态的胜率即可。注意处理细节还是比较容易AC的。

 

代码(32MS):

 1 #include <cstdio>

 2 #include <iostream>

 3 #include <algorithm>

 4 #include <cstring>

 5 #include <cmath>

 6 using namespace std;

 7 typedef long long LL;

 8 #define FOR(i, s, t) for(int i = s; i <= t; ++i)

 9 

10 const int MAXS = 50010;

11 const int MAXN = 8;

12 const double EPS = 1e-8;

13 

14 double a[7][7][7][7][7][7];

15 

16 double solve(int p1, int p2, int p3, int p4, int p5, int p6) {

17     if(a[p1][p2][p3][p4][p5][p6] > EPS) return a[p1][p2][p3][p4][p5][p6];

18     if(p1 + p2 + p3 + p4 + p5 + p6 == 0) return 0;

19     int v1, v2, v3, v4, v5, v6;

20     double ret = 0;

21     for(int i = 1; i <= 6; ++i) {

22         double tmp = 0;

23         for(int j = 1; j <= 3; ++j) {

24             v1 = p1, v2 = p2, v3 = p3, v4 = p4, v5 = p5, v6 = p6;

25             int k = j;

26             if(v1 >= i && k) --v1, --k;

27             if(v2 >= i && k) --v2, --k;

28             if(v3 >= i && k) --v3, --k;

29             if(v4 >= i && k) --v4, --k;

30             if(v5 >= i && k) --v5, --k;

31             if(v6 >= i && k) --v6, --k;

32             if(k == j) continue;

33             tmp += 1./3 * (1 - solve(v1, v2, v3, v4, v5, v6));

34         }

35         if(tmp > ret) ret = tmp;

36         tmp = 0;

37         for(int j = 1; j <= 3; ++j) {

38             v1 = p1, v2 = p2, v3 = p3, v4 = p4, v5 = p5, v6 = p6;

39             int k = j;

40             if(v6 >= i && k) --v6, --k;

41             if(v5 >= i && k) --v5, --k;

42             if(v4 >= i && k) --v4, --k;

43             if(v3 >= i && k) --v3, --k;

44             if(v2 >= i && k) --v2, --k;

45             if(v1 >= i && k) --v1, --k;

46             if(k == j) continue;

47             tmp += 1./3 * (1 - solve(v1, v2, v3, v4, v5, v6));

48         }

49         if(tmp > ret) ret = tmp;

50     }

51     return a[p1][p2][p3][p4][p5][p6] = ret;

52 }

53 

54 int x[7], n;

55 

56 int main() {

57     //FOR(i1, 0, 6) FOR(i2, 0, 6) FOR(i3, 0, 6) FOR(i4, 0, 6) FOR(i5, 0, 6) FOR(i6, 0, 6)

58         //if(a[i1][i2][i3][i4][i5][i6] < EPS) solve(i1, i2, i3, i4, i5, i6);

59     while(scanf("%d", &n) != EOF && n) {

60         memset(x, 0, sizeof(x));

61         for(int i = 1; i <= n; ++i) scanf("%d", &x[i]);

62         printf("%.6f\n", solve(x[1], x[2], x[3], x[4], x[5], x[6]));

63     }

64 }
View Code

 

你可能感兴趣的:(game)