hdu 4405 Aeroplane chess (简单概率dp)

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=4405

题意:飞行棋。如果格子不是飞行点,扔骰子前进。否则直接飞到目标点。每个格子是唯一的飞行起点,但不是唯一的飞行终点。问到达或越过终点的扔骰子期望数。

思路:概率题正推,期望题逆推
我们先设dp状态,设dp[i]表示在点i到达终点的期望。
那么由于骰子只有6个不同的数字,那么很明显,在某一位置i能够到达的就是 i + j ( j [ 1 , 6 ] ) ,所以当逆推的时候,i也是由i+j这6个点得来的。又因为骰子掷出每个数字的概率是一样的,所以我们可以得到一个基本的递推式 d p [ i ] = 1 6 ( d p [ i + 1 ] + d p [ i + 2 ] + d p [ i + 3 ] + d p [ i + 4 ] + d p [ i + 5 ] + d p [ i + 6 ] ) + 1 ;

当然题目还给出了另外飞行棋走法,如果在u点和v点之间有一条路径,那么在逆推的时候,我们就可以直接令dp[u]=dp[v],因为两点一旦有路,那么u点就必然只能由v点到达(这是因为在正推的时候,u点只能到达v点,反过来也是一样的)。并且要为u点打上标记,说明这个点已经不用经过 1 6 d的那个式子的更新了。
最后结果就是dp[0];

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 10;
double dp[maxn];//表示到达i点的数学期望
int n, m;
int vis[maxn];

int main() {
    while(~scanf("%d%d", &n, &m), n + m) {
        vector<int>G[maxn];
        for(int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[v].push_back(u);
        }
        memset(dp, 0, sizeof(dp));
        memset(vis, 0, sizeof(vis));
        for(int i = n; i >= 0; i--) {
            if(i != n && !vis[i]) {
                for(int j = i + 1; j <= i + 6; j++) { //当前状态可以由6个状态得来
                    dp[i] += (dp[j] + 1.0) / 6;
                }
            }
            for(int j = 0; j < G[i].size(); j++) {
                int v = G[i][j];
                vis[v] = 1;
                dp[v] = dp[i];
            }
        }
        printf("%.4f\n", dp[0]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81177431