题目
大致题意
有n个格点,掷骰子 ( 1 − − 6 ) (1--6) (1−−6),超过n就胜利。现有m个跳跃点,到 x x x位置时可以直接飞到 y y y位置。问:从起点到终点掷骰子的期望次数。
思路
骰子每个面的概率为
1
/
6
1/6
1/6
d
p
[
i
]
dp[i]
dp[i]:从位置
i
i
i到达
n
n
n期望掷骰子的次数。所以
d
p
[
n
]
=
0
dp[n]=0
dp[n]=0
当到达
x
x
x位置时可以直接飞到
y
y
y位置说明
d
p
[
x
]
=
d
p
[
y
]
dp[x]=dp[y]
dp[x]=dp[y]
求期望从后往前推
d
p
[
i
]
=
(
d
p
[
i
+
1
]
+
d
p
[
i
+
2
]
+
d
p
[
i
+
3
]
+
d
p
[
i
+
4
]
+
d
p
[
i
+
5
]
+
d
p
[
i
+
6
]
)
/
6
+
1
dp[i]=(dp[i+1]+dp[i+2]+dp[i+3]+dp[i+4]+dp[i+5]+dp[i+6])/6+1
dp[i]=(dp[i+1]+dp[i+2]+dp[i+3]+dp[i+4]+dp[i+5]+dp[i+6])/6+1
加一操作:到达当前状态需要掷一次骰子。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define int long long
const int N = 1e5+10;
vector<int>v[N];
int vis[N];
double dp[N];
signed main(){
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,m,x,y;
while(cin>>n>>m&&(m+n)){
for(int i=1;i<=n;i++)v[i].clear();
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
for(int i=0;i<m;i++){
cin>>x>>y;
v[y].push_back(x);
}
for(int i=n;i>=0;i--){
if(i!=n&&!vis[i]){
for(int j=1;j<7;j++){
dp[i]+=dp[i+j]/6.0;
}
dp[i]+=1.0;
}
for(int j=0;j<v[i].size();j++){
vis[v[i][j]]++;
dp[v[i][j]]=dp[i];
}
}
printf("%.4lf\n",dp[0]);
}
return 0;
}