main
黄海 2 years ago
parent 08c804bb36
commit ec00ad8651

@ -6,7 +6,7 @@ double f[N][N][N][N][5][5];
int st[N][N][N][N][5][5];
int A, B, C, D;
//如果大小王翻出来放1里则a++,放2里b++,...
// 如果大小王翻出来放1里则a++,放2里b++,...
void add(int &a, int &b, int &c, int &d, int x) {
if (x == 1) a++;
if (x == 2) b++;
@ -18,38 +18,38 @@ void add(int &a, int &b, int &c, int &d, int x) {
f(a,b,c,d,x,y)
*/
double dfs(int a, int b, int c, int d, int x, int y) {
//记忆化,同时因为f为double类型不能使用传统的memset(0x3f)之类
//进行初始化并判断是否修改过只能再开一个st数组
// 记忆化,同时因为f为double类型不能使用传统的memset(0x3f)之类
// 进行初始化并判断是否修改过只能再开一个st数组
if (st[a][b][c][d][x][y]) return f[a][b][c][d][x][y];
st[a][b][c][d][x][y] = 1;
//递归出口当前状态是否到达目标状态目标状态的期望值是0
int ta = a, tb = b, tc = c, td = d; //抄出来
add(ta, tb, tc, td, x), add(ta, tb, tc, td, y); //大王小王会改变四个花色的数量
// 递归出口当前状态是否到达目标状态目标状态的期望值是0
int ta = a, tb = b, tc = c, td = d; // 抄出来
add(ta, tb, tc, td, x), add(ta, tb, tc, td, y); // 大王小王会改变四个花色的数量
if (ta >= A && tb >= B && tc >= C && td >= D) return 0;
//当前状态下的剩余牌数量
// 当前状态下的剩余牌数量
int rst = 54 - ta - tb - tc - td;
if (rst == 0) return INF; //还没有完成目标,没有剩余的牌了,无解
if (rst == 0) return INF; // 还没有完成目标,没有剩余的牌了,无解
//当前状态可以向哪些状态转移
// Q:v为什么要初始化为1?
// A:看题解内容
// 当前状态可以向哪些状态转移
// Q:v为什么要初始化为1?
// A:看题解内容
double v = 1;
if (a < 13) //黑桃有剩余,可能选出的是黑桃
if (a < 13) // 黑桃有剩余,可能选出的是黑桃
v += dfs(a + 1, b, c, d, x, y) * (13 - a) / rst;
if (b < 13) //红桃有剩余,可能选出的是红桃
if (b < 13) // 红桃有剩余,可能选出的是红桃
v += dfs(a, b + 1, c, d, x, y) * (13 - b) / rst;
if (c < 13) //梅花有剩余,可能选出的是梅花
if (c < 13) // 梅花有剩余,可能选出的是梅花
v += dfs(a, b, c + 1, d, x, y) * (13 - c) / rst;
if (d < 13) //方块有剩余,可能选出的是方块
if (d < 13) // 方块有剩余,可能选出的是方块
v += dfs(a, b, c, d + 1, x, y) * (13 - d) / rst;
//如果小王没有被选出
// 如果小王没有被选出
if (x == 0)
v += min(min(dfs(a, b, c, d, 1, y), dfs(a, b, c, d, 2, y)), min(dfs(a, b, c, d, 3, y), dfs(a, b, c, d, 4, y))) / rst;
//如果大王没有被选出
// 如果大王没有被选出
if (y == 0)
v += min(min(dfs(a, b, c, d, x, 1), dfs(a, b, c, d, x, 2)), min(dfs(a, b, c, d, x, 3), dfs(a, b, c, d, x, 4))) / rst;
@ -58,11 +58,11 @@ double dfs(int a, int b, int c, int d, int x, int y) {
int main() {
cin >> A >> B >> C >> D;
//① 终点状态不唯一,起点是唯的的,所以以起点为终点,以终点为起点,反着推
//② AcWing 217. 绿豆蛙的归宿 需要建图,本题不用建图
double res = dfs(0, 0, 0, 0, 0, 0); //四种花色、大小王都还没有被抽取
// ① 起点状态不唯一,终点是唯一的,所以以起点为终点,以终点为起点,反着推
// ② AcWing 217. 绿豆蛙的归宿 需要建图,本题转移关系清晰,不用建图
double res = dfs(0, 0, 0, 0, 0, 0); // 四种花色、大小王都还没有被抽取
if (res > INF / 2) //因为是浮点数不能用等号判断是不是相等简单的办法就是INF/2
if (res > INF / 2) // 因为是浮点数不能用等号判断是不是相等简单的办法就是INF/2
puts("-1.000");
else
printf("%.3f\n", res);

@ -38,10 +38,6 @@ $0≤A,B,C,D≤15$
### 二、题意分析
<font color='red' size=4><b>$Q$:为什么从终止状态向起始状态递推?</b></font>
**答**:满足条件的终止状态较多,而起始状态唯一。考虑以终止状态为初值,起始状态为目标,进行动态规划。
#### 状态表示
$f[a][b][c][d][x][y]$ : 当前已翻开状态下,还需翻开牌的数量 **期望数**。

Loading…
Cancel
Save