LightOJ 1364 树形DP
52张扑克牌,问拿到指定数量的4个花色的最少次数期望是多少,其中拿到joker必须马上将其视作一种花色,且要使后续期望最小。
转移很容易想到,主要是两张joker的处理,一个状态除了普通的4个方向的转移,当没拿到joker时还要增加拿到joker的期望,根据题意直接在当前状态下找最小的期望计算即可。
/** @Date : 2017-08-29 17:58:59 * @FileName: LightOJ 1364 概率DP.cpp * @Platform: Windows * @Author : Lweleth (SoungEarlf@gmail.com) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h> #define LL long long #define PII pair<int ,int> #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1 ,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1e5+20; const double eps = 1e-8; double dp[15][15][15][15][5][5]; int A, B, C, D; double dfs(int a, int b, int c, int d, int x, int y) { if(dp[a][b][c][d][x][y] > -1) return dp[a][b][c][d][x][y]; double tot = a + b + c + d + (x==0?1:0) + (y==0?1:0); int pa = 13 - a, pb = 13 - b, pc = 13 - c, pd = 13 - d; if(x == y && x == 1) pa += 2;// else if(x == 1 || y == 1) pa++; if(x == y && x == 2) pb += 2;// else if(x == 2 || y == 2) pb++; if(x == y && x == 3) pc += 2;// else if(x == 3 || y == 3)pc++; if(x == y && x == 4) pd += 2;// else if(x == 4 || y == 4) pd++; if(pa >= A && pb >= B && pc >= C && pd >= D) return dp[a][b][c][d][x][y] = 0; // double ans = 0.0; if(a) ans += (double)a / tot * dfs(a - 1, b, c, d, x, y) * 1.000000000; if(b) ans += (double)b / tot * dfs(a, b - 1, c, d, x, y) * 1.000000000; if(c) ans += (double)c / tot * dfs(a, b, c - 1, d, x, y) * 1.000000000; if(d) ans += (double)d / tot * dfs(a, b, c, d - 1, x, y) * 1.000000000; if(x == 0) { double e = 0x7f; for(int i = 1; i <= 4; i++) e = min(e, dfs(a, b, c, d, i, y)); ans += (1.00000 / tot) * e; } if(y == 0) { double e = 0x7f; for(int i = 1; i <= 4; i++) e = min(e, dfs(a, b, c, d, x, i)); ans += (1.00000 / tot) * e; } //cout << "~" << endl; return dp[a][b][c][d][x][y] = ans + 1; } int main() { int T; cin >> T; int icase = 0; while(T--) { scanf("%d%d%d%d", &A, &B, &C, &D); memset(dp, 0xc2, sizeof(dp)); //cout << ******dp << endl; int cnt = (A-13>0?A-13:0) + (C-13>0?C-13:0) + (B-13>0?B-13:0) + (D-13>0?D-13:0); if(cnt > 2) printf("Case %d: -1\n", ++icase); else printf("Case %d: %.10lf\n", ++icase, dfs(13,13,13,13,0,0)); } return 0; }