思路:首先对于期望有如下定义:
E(a*X+b*Y)=a*E(X)+b*E(Y),现在要求事件X和事件Y同时发生的期望是等于他们的分别发生的概率乘上对应事件的值,同时也可以转化为X事件的期望值乘上X事件发生的概率a加上Y事件的期望值乘上Y事件发生的概率b就是两件事同时发生的期望值。
原题要求路径长度的期望,定义f[i]为从i到N的期望路径长度,有f[N]=0,要求f[1]
假设现在有一个点i可以到达点s1,s2,s3,s4,则f[i]=1/4*(w1+f[s1])+1/4*(w2+f[s2])+1/4*(w3+f[s3])+1/4*(w4+f[s4]),这里可以发现,要求每个点的f[i]都要先知道出点的f[]值,可以按照拓扑序从后往前推,也可以用记忆化搜索。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10,M=2e5+10;
int n,m;
int h[N],e[M],ne[M],w[M],idx;
int dout[N];
double f[N];
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
double dp(int u)
{
if(f[u]>=0) return f[u];
f[u]=0;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
f[u]+=(w[i]+dp(j))/dout[u];
}
return f[u];
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
dout[a]++;
}
memset(f,-1,sizeof f);
printf("%.2lf",dp(1));
return 0;
}
思路:这道题需要像上面一样找到合理的状态定义和状态表示的一个转移图。
定义一个状态f[a][b][c][d][x][y]为取得a 张黑桃、b 张红桃、c 张梅花、d 张方块,以及大王小王的状态为x,y下的期望值,初始状态x,y置为4,a~d置为0,表示一张牌都没有的情况。
终点状态就是f[A][B][C][D][x][y]里面x,y的不同情况里面期望最小的一种。
要查看当牌堆里面还有多少张牌就是sum=54-(a-b-c-d-(x!=4)-(y!=4)),对于下一张牌的概率这里用黑桃做演示,就是(13-a)/sum,用剩余牌中黑桃的数量除剩余牌的数量,就是下一张牌是黑桃的概率,仅当黑桃还有牌在牌堆。
大小王的概率就是1/sum,仅当大小王还没被抽出来。
大小王抽出来用到四个花色得到的期望需要选出最大的一个类加回当前状态的期望中。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=14;
const double INF=1e20;
int A,B,C,D;
double f[N][N][N][N][5][5];
double dp(int a,int b,int c,int d,int x,int y)
{
double &v=f[a][b][c][d][x][y];
if(v>=0) return v;
int as=a+(x==0)+(y==0);
int bs=b+(x==1)+(y==1);
int cs=c+(x==2)+(y==2);
int ds=d+(x==3)+(y==3);
if(as>=A&&bs>=B&&cs>=C&&ds>=D) return v=0;//当前状态已经是边界状态了
int sum=a+b+c+d+(x!=4)+(y!=4);
sum=54-sum;
if(sum<=0) return v=INF;
v=1;
if(a<13) v+=(13.0-a)/sum*dp(a+1,b,c,d,x,y);
if(b<13) v+=(13.0-b)/sum*dp(a,b+1,c,d,x,y);
if(c<13) v+=(13.0-c)/sum*dp(a,b,c+1,d,x,y);
if(d<13) v+=(13.0-d)/sum*dp(a,b,c,d+1,x,y);
if(x==4) //当大小王还没被抽出来
{
double t=INF;
for(int i=0;i<4;i++)
t=min(t,1.0/sum*dp(a,b,c,d,i,y));
v+=t;
}
if(y==4)
{
double t=INF;
for(int i=0;i<4;i++)
t=min(t,1.0/sum*dp(a,b,c,d,x,i));
v+=t;
}
return v;
}
int main()
{
cin>>A>>B>>C>>D;
memset(f,-1,sizeof f);
double t=dp(0,0,0,0,4,4);
if(t>INF/2) t=-1;
printf("%.3lf\n",t);
return 0;
}