【期望dp】 绵羊跳弹簧
>>>>题目
【题目】
T 组数据。对于每一组数据,有n+1 个格子从0 到n 标号,绵羊从0 号结点开始,每次若在 x 位置掷骰子,令掷出的数为num,则跳到 x+num 处。
另外还有 m 个弹簧,绵羊跳到一个有弹簧的格子上时,不需要掷骰子便可向右跳到某个位置(若此时仍有弹簧将继续向右跳),直到到达 n 或者超出 n 停止。
询问绵羊掷骰子的期望次数。
【输入格式】
第一行为一个整数T,表示数据组数。
接下来对于每组数据:首先一行两个数n, m,含义如题目所述,接下来每行两个数 a, b,
表示在格子 a 处有一个弹簧,将跳到格子 b 上(保证b>a)。
【输出格式】
输出T 行,每行一个实数,表示保留两位小数后的答案。
【输入样例】
2
2 0
8 3
2 4
4 5
7 8
【输出样例】
1.17
2.34
>>>>分析
看到题目,我们想到每一次的期望跳跃次数是由前面跳过的格子的期望次数推知的。
也就是说跳到下一个格子只与现在跳到的格子有关,与之前跳过的格子已经没有关系了,于是我们考虑使用dp(无后效性)
定义 dp[i] 表示 “在第 i 个格子跳到终点需要的期望步数”
那么怎样赋初值呢?练过许多期望和概率dp的题可以发现:
期望dp一般是倒推,概率dp一般是正推
因为在最后一个格子的时候已经跳到终点了,所以期望跳跃步数是0。然后再反向倒推回去,答案就是dp[0]
初值:dp[n]=0 答案dp[0]
想清楚了初值和答案,我们来想想递推式,从两种情况入手:
(一)绵羊没有跳弹簧
没有跳弹簧就说明可以从i点跳到i+1~i+6点,由
dp[i]+=(dp[i+j]+1)/6 (1<=j<=6)
dp[i+j]表示从i+j这个点跳到了i点(倒推),加一是因为扔了一次骰子,除以6相当于有六分之一的概率扔到1~6中的某一个数
(二)绵羊跳了弹簧
定义jmp[i]=j表示绵羊可从i点跳到j点,因为有弹簧不用扔骰子,转移方程为:
dp[i]=dp[jmp[i]]
多组数据记得清零噢!
【代码】
#include<bits/stdc++.h> #define maxn 100005 using namespace std; int jmp[maxn],n,m,T,a,b; double dp[maxn]; void clear() { memset(jmp,0,sizeof(jmp)); memset(dp,0,sizeof(dp)); } void solve() { dp[n]=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); jmp[a]=b; } for(int i=n-1;i>=0;i--) { dp[i]=0; if(!jmp[i]) { for(int j=1;j<=6;j++) dp[i]+=(dp[i+j]+1)/6; } else dp[i]=dp[jmp[i]]; } printf("%.2lf ",dp[0]); } int main() { freopen("sheep.in","r",stdin); freopen("sheep.out","w",stdout); scanf("%d",&T); while(T--) { clear(); solve(); } return 0; }
完结撒花✿✿ヽ(°▽°)ノ✿诶嘿嘿嘿嘿嘿
纪念一下下小友第一次写博客
题目来源 :2019.2.19杨雅儒学长的考试题