期望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 }
View Code

 

 

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 }
View Code

有向无环图  所以有拓扑序,所以按照拓扑序来期望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 }
View Code

定义状态 dp[a][b][c][d][x][y]  然后 每次翻牌有6种可能, 并且每次翻牌要翻牌次数加1  然后去搜其他的状态

状态看成是点, 概率看成是边即可

posted @ 2020-11-03 13:11  canwinfor  阅读(33)  评论(0)    收藏  举报