HDU4405 Aeroplane chess (概率DP,转移)

时间:2022-12-03 15:38:17

http://acm.hdu.edu.cn/showproblem.php?pid=4405

题意:在一个1×n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点。求走到n或超出n期望掷色子次数

分析:简单的题目,拿来入门很不错:

如果没有飞机的线 ,这题就是直接 dp[i]+=dp[i+x]/6 +1 了 ; 当前的期望由子期望相加 ; 那航线怎么考虑呢?一开始我以为是加上可以走到点的dp[v] ,可是仔细推敲这是不对了,在注意到航线的转移是不需要价值的,所以直接dp[u]=dp[v] 就好;为什么呢?很简单,例如: 7->8   , 因为8是可以直接由7来的,那8就继承7的期望

#include<bits/stdc++.h>
using namespace std; vector<int>G[];
bool vis[];
double dp[];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==&&m==) break;
for(int i= ; i<=n ; i++)
G[i].clear();
for(int i= ; i<m ; i++)
{
int u,v;scanf("%d%d",&u,&v);
G[v].push_back(u);
}
memset(dp,,sizeof(dp));
memset(vis,,sizeof(vis)); for(int i= ; i<G[n].size() ; i++)
{
int v=G[n][i];
dp[v]=;
vis[v]=;
}
for(int i=n- ; i>= ; i--)
{
if(vis[i]==){
for(int x= ; x<= ; x++)
{
dp[i]+=dp[i+x]/6.0;
}
dp[i]++;}
for(int j= ; j<G[i].size() ; j++)
{
int v=G[i][j];
dp[v]=dp[i];
vis[v]=;
}
}
printf("%.4lf\n",dp[]);
}
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 100010 double dp[N];
int nxt[N]; int main()
{
int n, m;
while(~scanf("%d%d", &n, &m), n+m) {
memset(nxt, -, sizeof(nxt));
for(int i = ; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
nxt[u] = v;
}
memset(dp, , sizeof(dp));
double dec = (double) / ;
for(int i = n - ; i >= ; i--) {
if(nxt[i] != -) {
dp[i] = dp[nxt[i]]; //如果可以飞,就直接把上一步的值赋给它
continue;
}
for(int j = ; j <= ; j++) {
if(i + j <= n) {
dp[i] += dp[i + j] * dec; //不能飞的话,就掷骰子为1-6的概率都为1/6,递推
}
}
dp[i]++; //走到下一步要+1
}
printf("%.4f\n", dp[]);
}
return ;
}