性质:
算法实现:
- 记忆化搜索
- DP
应用一(基础):
思路:因为是有向无环图,所以可以运用记忆化搜索,当前点的期望就等于每一条出边的权值乘于此边的概率(出度分之一)
code:
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int N=1e5+20,M=2e5+20;
int n,m;
int dout[N];
int h[N],e[M],w[M],ne[M],idx;
double f[N];
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
double find(int x){
if(f[x]>=0) return f[x];
f[x]=0;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
f[x]+=(w[i]+find(j))/dout[x];
}
return f[x];
}
int main(){
// freopen("123.in","r",stdin);
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
for(int i=1;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\n",find(1));
return 0;
}
应用二:
思路:记忆化搜索 f[a][b][c][d][x][y]代表此状态到达目标状态需要牌数的期望,x/y:0-3代表分配给a/b/c/d哪一种,4代表还未获取到此牌。
code:
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const double INF=1e20;
int A,B,C,D;
double f[15][15][15][15][5][5];
double find(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 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 * find(a + 1, b, c, d, x, y);
if (b < 13) v += (13.0 - b) / sum * find(a, b + 1, c, d, x, y);
if (c < 13) v += (13.0 - c) / sum * find(a, b, c + 1, d, x, y);
if (d < 13) v += (13.0 - d) / sum * find(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 * find(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 * find(a, b, c, d, x, i));
v += t;
}
return v;
}
int main(){
// freopen("123.in","r",stdin);
scanf("%d%d%d%d",&A,&B,&C,&D);
double ans=INF;
memset(f,-1,sizeof f);
ans=find(0,0,0,0,4,4);
if(ans>INF/2){
ans=-1;
}
printf("%.3lf\n",ans);
return 0;
}