题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4405
题意:
你在下简化版飞行棋。。。
棋盘为一个线段,长度为n。
上面有m对传送门,可以直接将你从a[i]传送到b[i]处。
每扔一次骰子,可以向前移动的步数为骰子的点数。
你的初始位置为0。当位置>=n时,游戏结束。
问你扔骰子次数的期望。
题解:
表示状态:
dp[i] = rest steps
位置为i时,剩余需要掷骰子次数的期望。
找出答案:
ans = dp[0](初始位置)
如何转移:
每次掷骰子点数分别为1至6的概率均为1/6。
dp[i] = sigma (dp[i+j] * 1/6) + 1
特别地,当i为某个传送门的入口时,只能转移到出口处。所以此时dp[i] = dp[trans[i]].
边界条件:
set dp = 0
i >= n表明游戏已经结束,dp[i]为0.
i < n的dp[i]会在for循环中更新,所以不用管。
AC Code:
1 // state expression: 2 // dp[i] = rest steps 3 // i: present pos 4 // 5 // find the answer: 6 // ans = dp[0] 7 // 8 // transferring: 9 // now: dp[i] 10 // dp[i] = sigma (dp[i+j] * 1/6) + 1 11 // 12 // boundary: 13 // set dp = 0 14 #include <iostream> 15 #include <stdio.h> 16 #include <string.h> 17 #define MAX_N 100010 18 19 using namespace std; 20 21 int n,m; 22 int trans[MAX_N]; 23 double dp[MAX_N]; 24 25 void read() 26 { 27 memset(trans,-1,sizeof(trans)); 28 int a,b; 29 for(int i=0;i<m;i++) 30 { 31 cin>>a>>b; 32 trans[a]=b; 33 } 34 } 35 36 void solve() 37 { 38 memset(dp,0,sizeof(dp)); 39 for(int i=n-1;i>=0;i--) 40 { 41 if(trans[i]!=-1) 42 { 43 dp[i]=dp[trans[i]]; 44 continue; 45 } 46 for(int j=1;j<=6;j++) 47 { 48 dp[i]+=dp[i+j]/6.0; 49 } 50 dp[i]+=1.0; 51 } 52 } 53 54 void print() 55 { 56 printf("%.4f ",dp[0]); 57 } 58 59 int main() 60 { 61 while(cin>>n>>m) 62 { 63 if(n==0 && m==0) break; 64 read(); 65 solve(); 66 print(); 67 } 68 }