main
黄海 2 years ago
parent ec00ad8651
commit e6fa8bbec0

@ -3,7 +3,6 @@ using namespace std;
const int N = 15;
const int INF = 0x3f3f3f3f;
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++,...
@ -18,23 +17,19 @@ 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数组
if (st[a][b][c][d][x][y]) return f[a][b][c][d][x][y];
st[a][b][c][d][x][y] = 1;
// 记忆化搜索
if (f[a][b][c][d][x][y] > 0) return f[a][b][c][d][x][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 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:看题解内容
double v = 1;
if (a < 13) // 黑桃有剩余,可能选出的是黑桃
v += dfs(a + 1, b, c, d, x, y) * (13 - a) / rst;
@ -58,8 +53,7 @@ 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); // 四种花色、大小王都还没有被抽取
if (res > INF / 2) // 因为是浮点数不能用等号判断是不是相等简单的办法就是INF/2

@ -13,6 +13,18 @@ $Rainbow$ 想问问 $Admin$,得到 $A$ 张黑桃、$B$ 张红桃、$C$ 张梅
特殊地,如果翻开的牌是大王或者小王,$Admin$ 将会把它作为某种花色的牌放入对应堆中,使得放入之后 $E$的值尽可能小。
> <font color='red' size=3><b> 注:从牌堆里面翻出来的牌的期望张数最少是多少? </b></font>
> **期望**:用初等数学的语言去描述,就是平均值是多少。
> $Q:$为什么会有最少的概念出现的呢?这个数量不是固定的吗?
> 答:这是因为大王和小王可以被认为是其中四个花色中的某一种花色,这就导致产生了不同的事件。
> 放到红桃里是一种事件,放到黑桃里是一种事件,...,这四个事件的期望不一定相同!
> 选择就在大小王上,我们要选择一个期望张数最少的放法,问我们这个期望张数最小是多少。
###$yxc$经典语录
> **图中,点是状态表示,边是状态转移**。
> **理解**:前一个题中,需要建图,建图完成后才能用图进行状态表示和状态转移,本题,状态表示和状态转移都是很明确的,不需要建图。
> **总结** :动态规划是精髓,建图与否是表象。
由于 $Admin$ 和 $Rainbow$ 还在玩扑克,所以这个程序就交给你来写了。
**输入格式**
@ -66,10 +78,9 @@ using namespace std;
const int N = 15;
const int INF = 0x3f3f3f3f;
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++;
@ -81,38 +92,34 @@ 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数组
if (st[a][b][c][d][x][y]) return f[a][b][c][d][x][y];
st[a][b][c][d][x][y] = 1;
// 记忆化搜索
if (f[a][b][c][d][x][y] > 0) return f[a][b][c][d][x][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;
// 递归出口当前状态是否到达目标状态目标状态的期望值是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:看题解内容
// 当前状态可以向哪些状态转移
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;
@ -121,11 +128,10 @@ 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); //四种花色、大小王都还没有被抽取
if (res > INF / 2) //因为是浮点数不能用等号判断是不是相等简单的办法就是INF/2
double res = dfs(0, 0, 0, 0, 0, 0); // 四种花色、大小王都还没有被抽取
if (res > INF / 2) // 因为是浮点数不能用等号判断是不是相等简单的办法就是INF/2
puts("-1.000");
else
printf("%.3f\n", res);
@ -133,16 +139,18 @@ int main() {
}
```
### 四、期望值为什么初始化为$1$?
#### $Q$:期望值为什么初始化为$1$?
$f[i]$: 从$i$卡牌状态到终点状态所需要的**期望卡牌数**
<center><img src='https://img-blog.csdnimg.cn/4479c699431c421da4ab5d4f3f3db1bc.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzUxOTY4MTU1,size_16,color_FFFFFF,t_70'></center>
$f[v_i]$: 从$i$卡牌状态到终点状态所需要的**期望卡牌数**
每次抽一张牌变到下个状态,所以每条路径的权值为$1$
$$\large f[v]=p_1×(f[1]+1)+p_2×(f[2]+1)+p_3×(f[3]+1)+…+p_k×(f[k]+1) = \\
\sum_{i=1}^{k}p_i+\sum_{i=1}^{k}p_i \times f[i]
$$\large f[v]=p_1×(f[v_1]+1)+p_2×(f[v_2]+1)+p_3×(f[v_3]+1)+…+p_k×(f[v_k]+1) = \\
\sum_{i=1}^{k}p_i+\sum_{i=1}^{k}p_i \times f[v_i]
$$
 因为$v$一定能到达下个局面,所以下个状态的概率和为$1$,这里的$\large \displaystyle \sum_{i=1}^{k}p_i=1$ 那么就有:$\displaystyle \large f[v]=1+\sum_{i=1}^{k}p_i \times f[i]$ 
综上这里的$f[v]$可以初始化为$1$
<center><img src='https://img-blog.csdnimg.cn/4479c699431c421da4ab5d4f3f3db1bc.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzUxOTY4MTU1,size_16,color_FFFFFF,t_70'></center>
 因为$v$一定能到达下个局面,所以下个状态的概率和为$1$,这里的$\large \displaystyle \sum_{i=1}^{k}p_i=1$ 那么就有:$\displaystyle \large f[v]=1+\sum_{i=1}^{k}p_i \times f[v_i]$ 
综上这里的$f[v]$可以初始化为$1$

Loading…
Cancel
Save