1. 程式人生 > >【期望dp】綿羊跳彈簧

【期望dp】綿羊跳彈簧

esp oid c++ eof color stdout 下一個 ems tro

【期望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\n",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楊雅儒學長的考試題

【期望dp】綿羊跳彈簧