这个周刷了很多概率期望有关的dp题目,缘起2016青岛D题和取log的神操作题HDU 5988 2016青岛区域赛 (最小费用流)

这类题目没有固定的模板,而且概率可以很容易插入一些经典模型,比如下面的 TSP。最小费用流。
我刷的这部分题目,无一例外均可用dp解决,主要是找到状态,很多题目都可以抽象成马尔科夫链

下面记录一下刷的经典题目

B - Discovering Gold

一排1到n的格子,每个格子上有黄金 aia_i ,你最开始在 11 号,每一次投塞子决定到哪一个格子,不能超出范围,你到了哪个格子就得到哪个格子的金币,问最终在nn 能得到金币的期望

思路

在第ii 个格子能转移到 i+j,i+j≤n,j≤6i+j,i+j\le n,j\le 6, 转移概率为能转移的格子数。,求出每个格子的概率,用概率乘上金币数目就是期望.

code

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-10
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 100+10;
const int MAX_V= 500+10;
const int MOD = 998244353;double dp[maxn];
int a[maxn];
int main()
{// ios_base::sync_with_stdio(0);// cin.tie(0);// cout.tie(0);int T;cin>>T;int kase =0;while (T--) {int n;cin>>n;ms(dp,0);double ans =0;for(int i =1 ; i<=n ; ++i)cin>>a[i];dp[1] = 1;for(int i=1 ; i <= n ; ++i){int k = min(6,n-i);for(int j =1 ; j<=k ; ++j)dp[j+i]+= dp[i]/k;}for(int i=1 ; i<=n ; ++i){ans += dp[i]*a[i];}printf("Case %d: %.9lf\n",++kase, ans);}//std::cout << "time "<< clock()/1000 <<"ms"<< '\n';return 0;
}

Island of Survival

(感谢A_LeiQ)翻译
被拉去参加一个野外求生……姑且这么叫吧。
岛上有t只老虎(T)和d只熊(D)还有自己(M)。每天会有两只生物相遇(自己也算)
T-M T会吃掉M
T-D T会吃掉D
D-D Nothing
M-D M可以选择杀与不杀D
T-T 两只T会互相残杀(Two Die)

问最终人类可以存货的概率(人类存活是指老虎都死光)

思路

这个问题其实很简单,遇到deer 不杀就行了,简单的想就是,杀了熊以后,老虎遇到你的概率就更大了,
设 dp[i][jdp[i][j 表示剩余 i老虎,j deeri老虎,j\ deer 时存活概率,用以上情况简单递推就好

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-10
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 1000+10;
const int MAX_V= 500+10;
const int MOD = 998244353;double dp[maxn][maxn];void dfs(int t, int d){if(t!=0){dp[t -2][d]+= dp[t][d] * t/(t+d+1)*(t-1)/(t+d);dfs(t-2,d);}if(d!=0){dp[t][d-1]+= dp[t][d]*2*t/(t+d+1)*d/(t+d);dfs(t,d-1);}
}
int main()
{// ios_base::sync_with_stdio(0);// cin.tie(0);// cout.tie(0);int T;cin>>T;int kase =0;while (T--) {int t,d;scanf("%d%d", &t,&d);// if(t ==0 ){//     printf("Case %d: %.9lf\n",++kase, 1.0);continue;// }// if(t & 1){//     printf("Case %d: %.9lf\n",++kase, 0.0);continue;//// }ms(dp,0);dp[t][d] = 1;for(int tt = t ; tt>=0 ; tt--){for(int dd = d ; dd >=0 ; dd--){int sum = tt*(tt-1)/2 + tt*dd + tt;if(sum==0)continue;if(tt>=2)dp[tt -2][dd]+= dp[tt][dd] * (tt-1)*tt/2/sum;if(dd)dp[tt][dd-1]+= dp[tt][dd]*tt*dd/sum;}}double ans =0;for(int i=0; i<=d ; ++i)ans +=dp[0][i];printf("Case %d: %.11lf\n",++kase, ans);}//std::cout << "time "<< clock()/1000 <<"ms"<< '\n';return 0;
}

注意求总的情况数的时候,deer遇到deer不会影响

Batting Practice

这个题是很经典的马尔科夫链模型,

投球,投不中的概率是 pp,连续投中 k1k_1 或者连续投不中 k2k_2 次,结束,问投球次数的期望.

思路

设 fif_{i} 表示连续 ii 次没投中,gig_i 表示连续 ii 次投中,则 fif_i 能转移到 fi+1,概率pf_{i+1},概率 p 或者 g1,1−pg_1,1-p,则fif_i 的期望关系有

fi=p∗(fi+1+1)+(1−p)∗(g1+1)

f_i = p*(f_{i+1} +1) + (1-p)*(g_1+1)
同理有 gig_i 解出 f1,g1f_1,g_1就好

code

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-8
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 2e3+10;
const int MAX_V= 500+10;
const int MOD = 998244353;
int main()
{int T;scint(T);int kase =0;while (T--) {double p;int m,n;scanf("%lf%d%d",&p,&m,&n );if(p < eps){printf("Case %d: %.9lf\n",++kase, m*1.0);continue;}else if(1-p < eps) {printf("Case %d: %.9lf\n",++kase, n*1.0);continue;}double q = 1-p;double k1 = (1.0 - pow(q,m-1.0))/p,k2 = (1.0-pow(p,n-1))/q;double f1 = k1*(1.0+k2*p)/(1.0-k1*k2*p*q);double g1 = k2*(q*f1+1.0);double ans = 1.0+ q*f1+p*g1;printf("Case %d: %.9lf\n",++kase, ans);}return 0;
}

Aladdin and the Magical Sticks

阿拉丁捡木棍,这题神坑,网上有 O(n)O(n) 的做法,但我一直不能理解.模型是邮票问题的扩展捡到一张可区分木根后其余木根的概率和均不可区分时应该不一样吧,为撒任然用不可区分时的模板来算?????????

dp做法

我是用的dpdp 做法
由于不可区分木根之间捡到的概率无差别,可区分也是一样,求出平均权重w1,w2w_1,w_2 ,
dp[i][j]dp[i][j] 表示分别捡到 i,ji,j根可区分和不可区分木根时的期望。则

dp[i][j]=(n−i)/s∗(dp[i+1][j]+w1)+(m−j)/s(dp[i][j+1]+w2)+j/s(dp[i][j]+w2)

dp[i][j] = (n-i)/s*(dp[i+1][j] + w_1) + (m-j)/s(dp[i][j+1] + w_2) + j/s(dp[i][j] + w_2)
解出 dp[i][j]dp[i][j],其中 ss 表示在 i,ji,j 点剩余能捡到木根总数 n,mn,m 分别表示可区分,和不可区分木根总数

code

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-10
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 5005;double dp[2][maxn];
int main()
{// ios_base::sync_with_stdio(0);// cin.tie(0);// cout.tie(0);int T;cin>>T;int kase =0;while (T--) {int N;scint(N);double w1 = 0,w2 = 0;int n =0,m =0;for(int i=0 ; i<N ; ++i){int w,num;scanf("%d%d",&w,&num );if(num==1)w1+=w,n++;else w2 += w,m++;}if(n)w1/=n;if(m)w2/=m;//std::cout << w1<<" " << w2 << '\n';ms(dp,0);for(int i = n ; i>=0 ; --i){for(int j = m ; j>=0 ; --j){if(i == n && j == m)continue;int s = n+m - i;//std::cout << s << '\n';dp[i%2][j] = (n-i)*(dp[(i+1)%2][j]+w1) + (m-j)*(dp[i%2][j+1]+w2) + j*w2;dp[i%2][j] /= (s-j);//std::cout << "dp["<<i<<"]["<<j<<"] ="<<dp[i][j]<< '\n';}}printf("Case %d: %.9lf\n",++kase,dp[0][0] );}//std::cout << "time "<< clock()/1000 <<"ms"<< '\n';return 0;
}

Where to Run TSP 问题

这个题的题目意思有点坑
感谢Flying_Fatty提供翻译和题解.

code

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-6
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 15;
int n,m;
int vis[1<<maxn][maxn];
double dp[1<<maxn][maxn];int G[maxn][maxn];bool dfs(int s,int u){if(s == (1<<n) - 1){dp[s][u] = 0;return 1;}if(vis[s][u])return dp[s][u] > eps;//可达vis[s][u] =1;int cnt =0;dp[s][u] = 5;for(int i =0 ; i<n ; ++i){if(G[u][i] && !(s&(1<<i)) && dfs(s|(1<<i),i)){int ns = s|(1<<i);dp[s][u] += G[u][i] + dp[ns][i];cnt++;}}if(cnt)dp[s][u]/=cnt;else dp[s][u] = 0;return cnt >0;
}int main()
{// ios_base::sync_with_stdio(0);// cin.tie(0);// cout.tie(0);int T;cin>>T;int kase =0;while (T--) {ms(vis,0);ms(dp,0);ms(G,0);scanf("%d%d",&n,&m );while (m--) {int u,v,t;scanf("%d%d%d", &u,&v,&t);G[u][v] = G[v][u] = t;}dfs(1,0);printf("Case %d: %.9lf\n",++kase,dp[1][0] );}//std::cout << "time "<< clock()/1000 <<"ms"<< '\n';return 0;
}

ACM概率期望dp刷题总结相关推荐

  1. ACM比赛经验、刷题记录及模板库总结(更新中)

    前言 本文所提及的部分题目代码,可以在我的Github上找到 第一部分 经验分享及感受 第二部分 刷题记录 一.基础算法&程序语言 //strlen()函数的复杂度是O(n)要小心 //截取字 ...

  2. 【loj6191】「美团 CodeM 复赛」配对游戏 概率期望dp

    题目描述 n次向一个栈中加入0或1中随机1个,如果一次加入0时栈顶元素为1,则将这两个元素弹栈.问最终栈中元素个数的期望是多少. 输入 一行一个正整数 n . 输出 一行一个实数,表示期望剩下的人数, ...

  3. [NOIP2016]换教室(概率期望$DP$)

    其实吧我老早就把这题切了--因为说实话,这道题确实不难啊--李云龙:比他娘的状压DP简单多了 今天我翻以前在Luogu上写的题解时,突然发现放错代码了,然后被一堆人\(hack\)--蓝瘦啊\(ORZ ...

  4. [概率期望DP]JZOJ 4212 我想大声告诉你

    Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一些人,小R 自然也参加了. 这个游戏有n 个人参加,每一轮随机选出一个还没有出局的人 ...

  5. 大佬(概率期望DP)

    首先根据数据范围,可以判断基本上是n^2的复杂度 通过分析我们发现每一次都可以从m个数中任意选,既然任意选,那么此时的概率的分母就是不变的,然而题中涉及的是某一段的最大值,所以我们按套路假设 f[i] ...

  6. HDU 4405 概率期望DP

    有 0到 n 个格子.掷骰子走路,求出到终点的数学期望,有飞行的路线. dp[i] 存储在i位置走到终点的期望. 转移方程dp[i]=(dp[i+1] ----> dp[i+6])/6+1; 有 ...

  7. bzoj3450 Easy(概率期望dp)

    3450: Tyvj1952 Easy Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 876  Solved: 648 [Submit][Statu ...

  8. bzoj2878 [Noi2012]迷失游乐园——概率期望DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878 这个博客写得很好:https://www.cnblogs.com/qt666/p/72 ...

  9. 【BZOJ2337】XOR和路径,概率期望DP+高斯消元

    Time:2016.08.27 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 与游走思路有一定相似的地方 对答案的每一位进行判断 通过高斯消元解出每个点到n xor路径为1的概率 ...

最新文章

  1. 科技|全球首款飞行汽车开始量产!下月开始预售,2023年后或可实现一键打“飞车”...
  2. CES现场低调的主线,近在咫尺的5G商业化 | CES2018技术趋势
  3. Http请求url参数字符集
  4. python中的单引号双引号和三引号
  5. notepad++默认的快捷键整理
  6. 阿里妈妈数据字化营销与MaxCompute的不解之缘
  7. 打包后找不到so_RTX 3090安装cuda11.1 找不到libcusolver.so.10
  8. python read函数参数_最新Pandas.read_excel()全参数详解(案例实操,如何利用python导入excel)...
  9. Altium Designer(五):布板技巧
  10. gcc(g++)头文件搜索路径与库文件搜索路径(转载)
  11. mysql修改字段的名称类型_MySQL修改字段名和字段数据类型
  12. 网课答案接口 查题系统
  13. C语言课设-单位车辆调度管理
  14. Python3实现Two-Pass算法检测区域连通性
  15. Qt小游戏教程之贪吃蛇(带源码)
  16. 关于2021年度一级建造师资格考试安徽考区考务工作有关事宜的通知
  17. 画论25 黄休复《益州名画录》
  18. Vite resolve.alias
  19. DROP TABLE, TRUNCATE TABLE, DELETE TABLE 三种删除语句的区别
  20. Alex Woodie:2019大数据预测

热门文章

  1. 揭秘精准诈骗,骗子为何知道你妈是谁
  2. 网站后台拿webshell
  3. 从睡眠期间的大脑活动检测痴呆症
  4. 一次JVM调优的笔记
  5. Discuz插件提示:对不起,您安装的不是正版应用的解决办法
  6. 微信小程序:多功能起名查重工具
  7. android 一键锁屏实现
  8. Windows核心编程(四)进程-1
  9. 解决微信小程序 wx.request 方法不支持 Promise 并发数问题
  10. 萝卜魂军曹机器人_《萝卜魂》参战作品详介第一弹:《交响诗篇》