题目链接:哆啦A梦传送门
题意:某个人要从1点走到n点,每次向右走的步数为抛骰子决定,骰子有六面,每面被抛出的概率为1/6。
此外,还有m条直达航线,每条为x,y,表示可以直接从点x到点y,而不用去抛骰子。
问:到达n点的期望抛骰子次数是多少?
题解:跟之前做的期望dp一个样。我们只要按有向图的路线走就行了。
设dp[i]为在i点,并且到目标位置的期望次数。
显然状态转移方程为:
总结下期望dp与概率dp的一般求解方法:
期望dp:(从后往前)
设dp[i]为到达某一条件,并且到目标条件的期望次数。状态转移方程为:
p[j]表示为从状态i转移到状态i+j的概率。
概率dp:(从前往后)
设dp[i]为到达某一条件的概率,状态转移方程为:
p[j]表示为状态从i-j转移到状态i的概率。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=100010;
double dp[N];
vector<int> vec[N];
bool vis[N];
int main()
{
int n,m;
while(~ scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
vec[i].clear();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
vec[v].push_back(u);
}
int len=vec[n].size();
dp[n]=0.0;
for(int i=0;i<len;i++)
{
int v=vec[n][i];
dp[v]=0.0;
vis[v]=true;
}
for(int i=n-1;i>=0;i--)
{
if(!vis[i]){
double item=0.0;
for(int j=1;j<=6;j++)
item+=dp[i+j];
item/=6.0;
dp[i]=item+1;
vis[i]=true;
}
len=vec[i].size();
for(int j=0;j<len;j++)
{
int v=vec[i][j];
dp[v]=dp[i];
vis[v]=true;
}
}
printf("%.4f\n",dp[0]);
}
return 0;
}