题意
有 5 个骰子, 14 个盒子.
玩 14 轮游戏, 每次投骰子, 你将骰子放入同一个之前没有放入的盒子中.
最大化在最优策略下玩家的分数.
玩家的分数这样计算:
设扔入的盒子的标号为 i .
当 1 <= i <= 6 时, 分数为 i 的个数 * i .
当 i = 7 时, 若有两对骰子相同, 分数为点数之和.
当 i = 8 时, 若至少有 3 个相同, 分数为点数之和.
当 i = 9 时, 若至少有 4 个相同, 分数为点数之和.
当 i = 10 时, 若 3 个相同, 另外两个也先相同, 分数为 25 .
当 i = 11 时, 若有连续 4 个, 分数为 30 .
当 i = 12 时, 若有连续 5 个, 分数为 40 .
当 i = 13 时, 若骰子分数都相同, 分数为 50 .
当 i = 14 时, 分数为点数之和.
分析
状压DP, f[x] 表示状态为 x , 到完结的最大期望分数.
f[x] = ∑ P(S) max(f[S + {i}] + w[S][i]) .
预处理每种状态放入每个盒子的分数 w[S][i] , 以及这种状态出现的概率 P[S] .
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <map> 6 using namespace std; 7 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 8 #define D(i, a, b) for (register int i = (a); i >= (b); i--) 9 #define db double 10 11 db p[10]; 12 13 int cnt[10]; 14 int idx, id[500], pos[50000]; 15 db P[500], w[500][15]; 16 17 void Prework(int dep, db Ps) { 18 if (dep > 5) { 19 int St = 0; F(i, 1, 6) St = St * 6 + cnt[i]; 20 21 bool tag = (pos[St] > 0); 22 if (!tag) id[++idx] = St, pos[St] = idx; 23 24 int Loc = pos[St]; 25 P[Loc] += Ps; 26 27 if (!tag) { 28 int sum = 0; F(i, 1, 6) sum += i * cnt[i]; 29 30 w[Loc][14] = sum; 31 32 bool Same = false; 33 F(i, 1, 6) if (cnt[i] == 5) Same = true; 34 if (Same) w[Loc][13] = 50; 35 36 bool Five = (cnt[2] > 0 && cnt[3] > 0 && cnt[4] > 0 && cnt[5] > 0); 37 if (Five && (cnt[1] > 0 || cnt[6] > 0)) 38 w[Loc][12] = 40; 39 40 bool Four = (cnt[1] > 0 && cnt[2] > 0 && cnt[3] > 0 && cnt[4] > 0); 41 Four |= (cnt[2] > 0 && cnt[3] > 0 && cnt[4] > 0 && cnt[5] > 0); 42 Four |= (cnt[3] > 0 && cnt[4] > 0 && cnt[5] > 0 && cnt[6] > 0); 43 if (Four) w[Loc][11] = 30; 44 45 bool Three = false, Two = false; 46 F(i, 1, 6) { 47 if (cnt[i] == 3) Three = true; 48 if (cnt[i] == 2) Two = true; 49 } 50 if (Three && Two) w[Loc][10] = 25; 51 52 Four = false; 53 F(i, 1, 6) if (cnt[i] >= 4) Four = true; 54 if (Four) w[Loc][9] = sum; 55 56 Three = false; 57 F(i, 1, 6) if (cnt[i] >= 3) Three = true; 58 if (Three) w[Loc][8] = sum; 59 60 int twocnt = 0; 61 F(i, 1, 6) twocnt += (cnt[i] >= 2); 62 if (twocnt >= 2) w[Loc][7] = sum; 63 64 F(i, 1, 6) w[Loc][i] = i * cnt[i]; 65 } 66 67 return; 68 } 69 F(w, 1, 6) { 70 cnt[w]++; 71 Prework(dep+1, Ps * p[w]); 72 cnt[w]--; 73 } 74 } 75 76 db f[20000]; 77 78 int main(void) { 79 #ifndef ONLINE_JUDGE 80 freopen("dices.in", "r", stdin); 81 #endif 82 83 int nT; scanf("%d", &nT); 84 F(cas, 1, nT) { 85 F(i, 1, 6) scanf("%lf", p+i); 86 87 idx = 0, memset(id, 0, sizeof id), memset(pos, 0, sizeof pos); 88 memset(P, 0, sizeof P), memset(w, 0, sizeof w); 89 Prework(1, 1); 90 91 memset(f, 0, sizeof f); 92 D(St, (1 << 14) - 2, 0) 93 F(Loc, 1, idx) { 94 db Max = 0; 95 F(Dec, 1, 14) if (~St >> Dec-1 & 1) 96 Max = max(Max, w[Loc][Dec] + f[St | (1 << Dec-1)]); 97 f[St] += P[Loc] * Max; 98 } 99 printf("Case #%d: %0.6lf\n", cas, f[0]); 100 } 101 102 return 0; 103 }
时间: 2024-12-29 12:17:24