等概率事件最优策略问题
仍然是从考试题说起
noip模拟74第\(3\)题
这个题的第一个结论,两人策略相同
而第一个人的最优策略并不能直接由当前的值推出来,而是需要从后面赢的概率得到当前策略
我们只需要对应的转移一下就行了,具体可以看那篇考试的题解
多校冲刺 noip 11.01第\(2\)题
和上面那个是一样的,只不过这个变成了期望
最优策略仍然是由后面的期望决定的
当前这一次的期望一定是可以选的范围的中点
可以直接倒推转移
一点总结
遇到这样的最优策略的题
可以先瞪眼,瞪出一些没有用的策略(当然这并没有什么用)
然后就可以开始倒推转移了,所有最优策略全是根据后面的概率或者期望得到的
所谓最优策略,不过是他也会像我们一样推出来整个游戏的概率然后选择了概率或者期望最大的那种操作
并不是像赌博一样我去赌某一种策略的胜率
而是在平均情况下最优的决策
就像是海盗分金,我们从后往前推的话,发现第一个人有这么大的权利啊
例题
大意:有一些钱要取出来,钱的数量在\([0,K]\)随机,取得少就可以取出来,取得多就要挨干,至多挨干\(W\)次,采取最优策略使得取钱次数最少,问期望次数
这个题仍然是看上去一点思路都没有
所以我就去看题解了,看完题解好像理解了一点点
首先我们仍然不知道最优策略是啥,可能你会觉得最优策略就是二分着取钱
二分的最劣情况不过是,取出来钱的次数+被警告的次数\(=log\)
没准赌一把取钱的次数更少呢??
如果警告次数上限小于\(log\)呢?只能是\(DP\)
所以我们继续刚才的思路:倒推!!!
枚举当前决策,从后面的状态转移
如果当前决策确定了,那么被警告和取出钱的概率也就确定了,也就是说转移系数确定了
\(dp_{i,j}\)表示当前钱数上限是\(i\),最多被警告\(j\)次的期望取钱次数
注意这里的\(j\)最大是\(log\),原因就是上面的二分思想
如果上限很大的话,我二分着取的次数可能是非常优秀的策略
简单来说,二分取钱在这个题里面是最劣的决策,因为他太保守!!!
code
#include<bits/stdc++.h>
using namespace std;
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2e3+5;
const int M=15;
int n,w;
double f[N][M];
signed main(){
fxt(i,0,2000)fxt(j,0,12)f[i][j]=1e9;
fxt(i,0,12)f[0][i]=0;
fxt(i,1,2000)fxt(j,1,12)fxt(k,1,i){
f[i][j]=min(f[i][j],f[i-k][j]*(i-k+1)/(i+1)+f[k-1][j-1]*k/(double)(i+1)+1);
}
while(scanf("%d%d",&n,&w)!=EOF){
w=min(w,12);printf("%.6lf\n",f[n][w]);
}
}
大意:有\(R\)张红牌,\(B\)张黑牌,一张一张的翻开,红牌给你一块,黑牌扣你一块,随时停止翻牌,最优策略下得到的钱数
这个比上一个要简单的多
我们仍然倒推,当一张牌也没有的时候,一定是\(0\)
我们每次转移,选红牌就\(+1\),黑牌就\(-1\),如果小于\(0\)了就把他变成\(0\)
直接输出就好了
code
#include<bits/stdc++.h>
using namespace std;
#define ld double
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=5005;
int n,m;
ld f[N][N];
signed main(){
scanf("%d%d",&n,&m);
fxt(i,0,n)fxt(j,0,m){
if(i>0&&j>0)f[i][j]=max(f[i][j],(f[i-1][j]+1.0)*i/(i+j)+(f[i][j-1]-1.0)*j/(i+j));
else if(i>0)f[i][j]=max(f[i][j],f[i-1][j]+1.0);
else if(j>0)f[i][j]=max(f[i][j],f[i][j-1]-1.0);
}
printf("%.6lf",f[n][m]-0.0000005);
}

浙公网安备 33010602011771号