概率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;
}