期望dp总结
期望dp 只能逆推
概率dp 只能顺推
附上大佬的博客链接:https://www.cnblogs.com/fusiwei/p/11743090.html
大佬的题目集: https://www.cnblogs.com/hua-dong/p/8166093.html
经典的邮票收集问题 https://blog.csdn.net/qq_34921856/article/details/80507686
题目链接:https://ac.nowcoder.com/acm/contest/9854/H
题解:https://ac.nowcoder.com/discuss/584247?type=101&order=0&pos=3&page=1&channel=-1&source_id=1
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define pb push_back 5 const int maxn =1e7+10; 6 const int mod=1e9+7; 7 double f[maxn]; 8 9 10 11 12 int main() 13 { 14 ios::sync_with_stdio(false); 15 cin.tie(0); 16 for(int i=1;i<maxn;i++) 17 { 18 f[i]=f[i-1]+1.0/i; 19 } 20 int t; 21 cin>>t; 22 while(t--) 23 { 24 int n; 25 cin>>n; 26 double ans=10000.0*f[n]+(n-1)*f[n]; 27 cout<<fixed<<setprecision(7)<<ans<<'\n'; 28 } 29 30 31 32 33 }
acwing
E(aX+bY)=aE(X)+bE(y) 这个性质 所以才能来用概率乘期望来递归 dp
a为 概率 X Y为 期望 所以= X发生的期望×概率a +Y发生的期望×概率b
思路都是考虑 建图 然后通过加上子状态
求期望的话 采用逆推 更
题目一:https://www.acwing.com/problem/content/219/ ###K
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int mod=1e9+7; 5 #define ll long long 6 #define ull unsigned long long 7 #define pb push_back 8 #define pi pair<int,int> 9 #define fi first 10 #define sc second 11 12 13 int n,m; 14 double dp[maxn]; 15 vector<pi>E[maxn]; 16 17 18 double dfs(int u) 19 { 20 if(u==n||dp[u]>0) return dp[u]; 21 int k=E[u].size(); 22 for(auto &v:E[u]) 23 { 24 dp[u]+=(dfs(v.fi)+v.sc)/k; 25 } 26 return dp[u]; 27 } 28 29 30 int main() 31 { 32 ios::sync_with_stdio(0); 33 cin.tie(0); 34 cin>>n>>m; 35 while(m--) 36 { 37 int u,v,w; 38 cin>>u>>v>>w; 39 E[u].pb({v,w}); 40 } 41 cout<<fixed<<setprecision(2)<<dfs(1)<<'\n'; 42 43 44 }
有向无环图 所以有拓扑序,所以按照拓扑序来期望dp即可 dp[i]为 从i开始走的长度
然后 用记忆化搜索保证拓扑序即可, (子状态没更新就去搜索子状态来保证拓扑序)
dp[i] 只能定义为 从i到n的期望 而不能定义成从 从1到i的期望长度
因为期望的性质 考虑一个点往外有k条边 每一条边的概率*上期望的和 加起来才=当前的dp[i]
题目二:https://www.acwing.com/problem/content/220/
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int mod=1e9+7; 5 #define ll long long 6 #define ull unsigned long long 7 #define pb push_back 8 #define pi pair<int,int> 9 #define fi first 10 #define sc second 11 const int M=20; 12 13 double f[M][M][M][M][5][5]; 14 int A,B,C,D; 15 16 double dp(int a,int b,int c,int d,int x,int y) 17 { 18 double &v=f[a][b][c][d][x][y]; 19 if(v>=0) return v; 20 21 int as=a+(x==0)+(y==0); 22 int bs=b+(x==1)+(y==1); 23 int cs=c+(x==2)+(y==2); 24 int ds=d+(x==3)+(y==3); 25 if(as>=A&&bs>=B&&cs>=C&&ds>=D) return v=0; 26 int sum=54-a-b-c-d-(x!=4)-(y!=4); 27 28 if(sum<=0) return v=1e9; 29 30 31 32 v=1; 33 if(a<13) v+=(13.0-a)/sum*dp(a+1,b,c,d,x,y); 34 if(b<13) v+=(13.0-b)/sum*dp(a,b+1,c,d,x,y); 35 if(c<13) v+=(13.0-c)/sum*dp(a,b,c+1,d,x,y); 36 if(d<13) v+=(13.0-d)/sum*dp(a,b,c,d+1,x,y); 37 38 if(x==4) 39 { 40 double t=1e9; 41 for(int i=0;i<4;i++) t=min(t,1.0/sum*dp(a,b,c,d,i,y)); 42 v+=t; 43 } 44 if(y==4) 45 { 46 double t=1e9; 47 for(int i=0;i<4;i++) t=min(t,1.0/sum*dp(a,b,c,d,x,i)); 48 v+=t; 49 } 50 51 return v; 52 53 } 54 55 56 57 int main() 58 { 59 ios::sync_with_stdio(0); 60 cin.tie(0); 61 cin>>A>>B>>C>>D; 62 memset(f,-1,sizeof(f)); 63 double ans=dp(0,0,0,0,4,4); 64 if(ans>1e9) ans=-1; 65 cout<<fixed<<setprecision(3)<<ans<<'\n'; 66 67 68 69 }
定义状态 dp[a][b][c][d][x][y] 然后 每次翻牌有6种可能, 并且每次翻牌要翻牌次数加1 然后去搜其他的状态
状态看成是点, 概率看成是边即可

浙公网安备 33010602011771号