期望与期望DP
Part 0 听雨闲话
雨终于停了……我的总结还没写完
Part 1 什么是"期望"?
数学期望(又称期望、平均值、一阶矩)是随机变量对概率分布的加权平均,表示随机变量的平均值。对于离散的概率分布,数学期望是随机变量取值与相应概率乘积的求和(摘自百度百科)
换句话说:
期望是我们对某一概率事件结果相对理性的估计:在平均计算的理想状态下,这一事件的结果可以被视为多少?
数学定义:
举例:
丢一颗骰子,获得点数的期望是多少?
也就是说: 当投掷骰子的次数足够大时,我们可以将每一次投掷的结果估计为3.5
Another举例:
发行一种彩票,该彩票的原理如下:
每张彩票3元,购买后随机生成一个六位数,将其与假定的中奖号码529222比较:
- 末位数字相同:获得1元
- 末2位数字相同:获得10元
- 末3位数字相同:获得100元
- 末4位数字相同:获得1000元
- 末5位数字相同:获得10000元
- 全部6位数字相同:获得100000元
请问,对于每张彩票,彩票公司期望的收益是多少?
答案:
即对于每张彩票,公司期望支付0.6元的奖金,则每张彩票收入2.4元。
看来发行彩票真是稳赚不赔的生意。
于是,现在可以用自己的话重新给 "期望" 定义了:
对于一种可能性事件,我们将对应的结果加权概率取平均值,以描述单个事件的平均结果。
Part 2 期望DP
例题:P1937 传传爆
有一个 n×m 的矩阵,左上角的格子记为 (1,1),右下角的格子记为 (n,m)。
格子要么是黑色的,要么是白色的。魔法少女从 (1,1) 出发寻找食物,按照如下规则移动:
- 每次可以向上下左右移动一步,但是不能出界。
- 如果移动到黑色格子,则无事发生。
- 如果移动到白色格子,魔法少女会被等概率独立随机传送到任意一个白色格子(包括她所在的格子)上。
- 传送完后可以继续移动。
当魔法少女到达 (n,m) 时,她会停止移动。魔法少女会最小化移动的期望次数。求出魔法少女移动的期望步数。
分析:
考虑经典的网格DP问题:由于最小化移动步数,只能向右或者向下走。
因此,每一格的步数应从其左侧和上方的格子继承。
对于黑格和白格,应分别讨论:
1.黑格
依据题意,走到黑格时无事发生。
因此,黑格的步数完全从左侧和上方的格子继承而来。
形式化地,有:$$step[i][j]=min(step[i-1][j],step[i][j-1])+1$$
2.白格
每次到达白格时,会触发随机传送,到达任意一个白格上。
因此,所有的白格可以视为一个整体:不管从何处进入白格,其效果都是等价的——随机到达任意一个白格上。
由此可得,所有白格的步数代价应为一个相同的值,记为E,代表进入白格,经过某些操作后离开白格,然后前往终点的平均期望步数。现在考虑一种策略,使得离开白格后前往终点的期望步数最优。
3.怎么走?
经过分析,不难想到以下几个规则:
- 不能离开白格后,走几步黑格,再次进入白格。
- 所有白格为一个整体,离开白格再次进入相当于兜了一个圈子,明显不优。
- 换言之,一旦决定离开白格,只能一路走黑格到达终点。
- 因此维护数组T,存储从每个格子处只走黑格到达终点的步数。
- 如果当前被传送到的白格位置不优,无法只走黑格到终点/终点太远,则我们考虑再次传送。
- 由于所有白格到终点的期望步数都为E,如果当前格子到终点的黑格距离T大于进入下一个白格的距离t+从下一个白格到终点的距离E,则重新进入白格传送。
- 如要再次传送,只有两种方案最优:
- 到达相邻的一个白格(如果有)
- 否则,走到相邻的黑格,再回到刚刚的白格
4.计算E的值
回顾公式:
这个公式中有两个参数:a(距离终点最优步数)和p(概率)。
由于每格等概率传送,无需考虑p,将公式变形为:
- 其中N为白格总数
由刚刚的规则可知:当前白格与终点距离=min(到达一个白格距离+白格期望距离,走黑格到终点距离)
形式化地,有:
将该式带入刚刚的式子,有:
设
则
发现这个式子两边都有E,无法对E求值,且式子右边E在min函数里,无法直接移项。
因此,考虑分段"拆掉"min函数:
设分段点为p,对p进行枚举:
从1~N遍历枚举p,当满足:
则此情况成立,得以计算出E。
参考代码实现:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9+7;
int Times,m,n,cnt;
int f[1005][1005],Tmp[1005][1005],Tmp2[1005][1005];
bool vis[1005][1005];
int dx[]={1,-1,0,0};
int dy[]={0,0,-1,1};
struct node{
int x,y,step;
};
struct white{
int T,t,d;
}w[1000005];
queue<node>q;
void bfs(node x,int Tmp[][1005])//广搜预处理Tmp数组
{
while(!q.empty())q.pop();
memset(vis,0,sizeof(vis));
if(f[x.x][x.y]==1)return;
q.push(x);
vis[x.x][x.y]=1;
Tmp[x.x][x.y]=x.step;
while(!q.empty())
{
node tmp=q.front();
q.pop();
for(int k=0;k<4;k++)
{
int nx=tmp.x+dx[k];
int ny=tmp.y+dy[k];
if(nx<1||nx>n||ny<1||ny>m)continue;
if(f[nx][ny]==1||vis[nx][ny])continue;
vis[nx][ny]=1;
Tmp[nx][ny]=tmp.step+1;
q.push((node){nx,ny,tmp.step+1});
}
}
}
int minn(int a,int b,int c,int d)
{
int res=inf;
if(a>=0&&a<res)res=a;
if(b>=0&&b<res)res=b;
if(c>=0&&c<res)res=c;
if(d>=0&&d<res)res=d;
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>Times;
while(Times--)
{
cin>>n>>m;
cnt=0;
//初始化
for(int i=0;i<=n+1;i++)
for(int j=0;j<=m+1;j++)
{
f[i][j]=0;
Tmp[i][j]=-1;
Tmp2[i][j]=-1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char c;
cin>>c;
if(c=='C')f[i][j]=0;
else f[i][j]=1;
}
}
//特判:n=m=1
if(n==1&&m==1)
{
cout<<"0/1\n";
continue;
}
//从终点BFS
bfs((node){n,m,0},Tmp);
//从起点BFS
bfs((node){1,1,0},Tmp2);
//如果没有白色格子
bool has_white=false;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(f[i][j]==1)has_white=true;
if(!has_white)
{
if(Tmp[1][1]!=-1)cout<<Tmp[1][1]<<"/1\n";
continue;
}
//预处理w数组
cnt=0;
long long sum_t=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(f[i][j]==1)
{
cnt++;
//计算t
bool adj_white=false;
for(int k=0;k<4;k++)
{
int nx=i+dx[k];
int ny=j+dy[k];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&f[nx][ny]==1)
{
adj_white=true;
break;
}
}
w[cnt].t=adj_white?1:2;
sum_t+=w[cnt].t;
//计算T:到终点的最短距离
w[cnt].T=inf;
for(int k=0;k<4;k++)
{
int nx=i+dx[k];
int ny=j+dy[k];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&f[nx][ny]==0)
{
if(Tmp[nx][ny]!=-1)
w[cnt].T=min(w[cnt].T,Tmp[nx][ny]+1);
}
}
if(w[cnt].T==inf)w[cnt].T=1e9;
w[cnt].d=w[cnt].T-w[cnt].t;
}
}
}
//按d排序
sort(w+1,w+cnt+1,[](const white& a,const white& b){
return a.d<b.d;
});
//求前缀和
vector<long long>sum_d(cnt+1,0);
for(int i=1;i<=cnt;i++)
sum_d[i]=sum_d[i-1]+w[i].d;
//计算期望E
long long PE=-1,P=-1;
for(int p=1;p<=cnt;p++)
{
long long nu=sum_d[p]+sum_t;
long long de=p;
//检查条件:w[p].d<=E<w[p+1].d
bool valid=true;
if((__int128)nu<(__int128)de*w[p].d)valid=false;
if(p<cnt&&(__int128)nu>=(__int128)de*w[p+1].d)valid=false;
if(valid)
{
PE=nu;
P=de;
break;
}
}
//计算最终答案
long long up=1e18,down=1;
//方案1:直接从起点走黑格到终点
if(Tmp[1][1]!=-1)
{
up=Tmp[1][1];
down=1;
}
//方案2:从起点走到白格,然后经过白格系统
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(f[i][j]==1)
{
//计算从起点到这个白格的距离
int dist=inf;
for(int k=0;k<4;k++)
{
int nx=i+dx[k];
int ny=j+dy[k];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&f[nx][ny]==0)
{
if(Tmp2[nx][ny]!=-1)
dist=min(dist,Tmp2[nx][ny]+1);
}
}
if(dist!=inf)
{
//比较:dist+P E/P
long long upp=(long long)dist*P+PE;
long long downn=P;
if((__int128)upp*down<(__int128)up*downn)
{
up=upp;
down=downn;
}
}
}
}
}
//化简
long long g=__gcd(up,down);
up/=g;
down/=g;
cout<<up<<"/"<<down<<"\n";
}
return 0;
}

浙公网安备 33010602011771号