Aeroplane chess HDU - 4405(期望dp)

题意:

飞行棋。有n+1格,开始时在0号格子,每一步都要扔一个dice(六个面,概率相同)哪一面朝上他就会向前走x+i步。当x+i大于等于N的时候,游戏结束。另外,地图上有m条航线。第i条航线可以直接从xi到yi。计算扔dice次数的期望。

题目:

Hzz loves aeroplane chess very much. The chess map contains N+1 grids labeled from 0 to N. Hzz starts at grid 0. For each step he throws a dice(a dice have six faces with equal probability to face up and the numbers on the faces are 1,2,3,4,5,6). When Hzz is at grid i and the dice number is x, he will moves to grid i+x. Hzz finishes the game when i+x is equal to or greater than N.

There are also M flight lines on the chess map. The i-th flight line can help Hzz fly from grid Xi to Yi (0<Xi<Yi<=N) without throwing the dice. If there is another flight line from Yi, Hzz can take the flight line continuously. It is granted that there is no two or more flight lines start from the same grid.

Please help Hzz calculate the expected dice throwing times to finish the game.

Input

There are multiple test cases.
Each test case contains several lines.
The first line contains two integers N(1≤N≤100000) and M(0≤M≤1000).
Then M lines follow, each line contains two integers Xi,Yi(1≤Xi<Yi≤N).
The input end with N=0, M=0.

Output

For each test case in the input, you should output a line indicating the expected dice throwing times. Output should be rounded to 4 digits after decimal point.

Sample Input

2 0
8 3
2 4
4 5
7 8
0 0

Sample Output

1.1667
2.3441

分析:

这个题有一个默认的条件,如果当前格子有航线可以选择,那么就一定选择航线而不是掷色子。
最简单的概率DP,状态的定义需要从后往前定义,因为航线的缘故只能从后往前转移。

n个方程,回带一下就行。f[n]=0,所有标号i大于n的期望值f[i]也为0. 有虫洞 对于任何一个虫洞,起点的期望等于终点的期望。
例子。
比如n=3,m=0
所列方程为f[0]=1/6f[1]+1/6f[2]+1/6f[3]+1
f[1]=1/6e[2]+1/6e[3]+1
f[2]=1/6e[3]+1
f[3]=0
从0这个点可以到1,2,3,4,5,6这几个位置,由于大于等于3游戏结束,不会再有期望的投色子次数了,所以跳到3和大于3的格子里期望值也就都是0了。
所以我们列出n个方程后直接回带就能把f[0]求出来。如f[3]=0可以求出f[2]=1,已知了f[2]和f[3]就可以求出f[1],进而求出f[0].
两层for循环就是一个回带的过程。
题目还有可以直接从a跳到b,不需要投色子的,那样就直接标记一下,a的期望值也就等于b的期望值。(a<b)

定义f[i]为 从第i个格子到n个格子的期望次数是多少。
如果i格子有航线那么 f[i]=f[to] ,to是航线可以到达的格子。
如果i格子没有航线,那么f[i]=sum(1/6*f[i+k])+1,其中k是色子的六个面(1,2,3,4,5,6)。

ac代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int M=1e5+10;
int n,m;
int dp[M];
double f[M];
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
    {
        memset(f,0,sizeof(f));
        memset(dp,-1,sizeof(dp));
        int x,y;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&x,&y);
            dp[x]=y;
        }
        for(int i=n-1; i>=0; i--)
        {
            if(dp[i]!=-1)
                f[i]=f[dp[i]];
            else
                for(int j=1; j<=6; j++)
                {
                    int to=min(n,i+j);
                    f[i]+=(f[to]+1)*(double)1/6;
                }
        }
        printf("%.4f\n",f[0]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zeng_jun_yv/article/details/105127597