题目链接:HDU 4405 Aeroplane chess
概率dp。
显然终点及终点之后的点的期望都是0。
反着建立了一个有向图,然后从后往前推期望,题目中有一些点可以直接到达下一个点而不用经过摇色子,如果碰见这样的点则必须飞过去而不能正常走。那么这些点如果走过(倒着走过的),就得设置一个标记表示走过了,正常走的时候不走这里。
正常走的时候计算期望就很简单了,dp[i] = 1 + dp[i + 1] * p + dp[i + 2] * p + dp[i + 3] * p + dp[i + 4] * p + dp[i + 5] * p + dp[i + 6] * p,其中p是常量,值为1.0 / 6.0。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX_N = 100000 + 100; const int MAX_M = 1000 + 10; const double p = 1.0 / 6.0; struct Edge { int v, next; }; Edge e[MAX_M]; int head[MAX_N], vis[MAX_N]; double dp[MAX_N]; int cnt, n, m, a, b; void addEdge(int u, int v) { e[cnt].v = v; e[cnt].next = head[u]; head[u] = cnt++; } int main() { while(scanf("%d%d", &n, &m), n + m) { memset(vis, 0, sizeof(vis)); memset(dp, 0, sizeof(dp)); memset(head, -1, sizeof(head)); cnt = 0; for(int i = 0; i < m; i++) { scanf("%d%d", &a, &b); addEdge(b, a); } for(int i = head[n]; i != -1; i = e[i].next) { dp[e[i].v] = 0; vis[e[i].v] = 1; } for(int i = n - 1; i >= 0; i--) { if(!vis[i]) dp[i] = 1 + dp[i + 1] * p + dp[i + 2] * p + dp[i + 3] * p + dp[i + 4] * p + dp[i + 5] * p + dp[i + 6] * p; for(int j = head[i]; j != -1; j = e[j].next) { dp[e[j].v] = dp[i]; vis[e[j].v] = 1; } } printf("%.4lf\n", dp[0]); } return 0; }