poj 3756
题目描述:
类似大富翁的游戏,给你一条长度为n的条状棋盘,起点为0号,终点为n号,一共有n 1个点。
每个点有4种状态:
1:无状态。
2:从此点往前走k步。
3:从此点往后退m步。
4:下一回合不能动。
每一回合仅能启用一种状态(比如中了状态2往前走k步后,刚好又碰到状态3,则状态3不起作用)
如果退到0点或者n点还有剩余的步可以走,则往相反的方向走(既不能丢弃多余的步,也不能走出棋盘)。
问你从0走到n所需的回合的期望。
解题报告:
dp,dp[i][j]表示第i回合走到第j号点的概率是多少,开始时dp[0][0] = 1,其他都为0.
若dp[i][j] != 0, 根据规则,容易求的从j开始抛骰子的以下六个位置记作pos[k], 0<= k < 6
如果走到pos[k]是启用的是状态4(下一回合不能动)
则dp[i+2][pos[k]]+ = dp[i][j] * (1 / 6)
否则 dp[i+1][pos[k]]+ = dp[i][j] * (1 / 6)
代码:
#include<iostream>
#include<fstream>
using namespace std;
int num1,num2,num3;
int a[101];
int b[101],c[101];
double dp[300][101];
int n;
int ok(int s){
while(1){
if(s>n) s=2*n-s;
else if(s<0) s=-s;
else return s;
}
}
void read(){
// ifstream cin("in.txt");
int i,j,k;
cin>>n;
cin>>num1;
for(i=1;i<=num1;i++)
{
cin>>j>>k;
a[j]=1;
b[j]=k;
}
cin>>num2;
for(i=1;i<=num2;i++)
{
cin>>j>>k;
a[j]=2;
c[j]=k;
}
cin>>num3;
for(i=1;i<=num3;i++)
{
cin>>j;
a[j]=3;
}
dp[0][0]=1;
for(i=0;i<200;i++)
{
for(j=0;j<n;j++)
if(dp[i][j]>0)
{
for(k=1;k<=6;k++)
{
int s=ok(j+k);
if(a[s]==3)
{
dp[i+2][s]+=dp[i][j]*1/6;
}
else
{
if(a[s]==1) s=ok(b[s]+s);
else if(a[s]==2) s=ok(s-c[s]);
dp[i+1][s]+=dp[i][j]*1/6;
}
}
}
}
double ans=0;
for(i=1;i<200;i++)
ans+=i*dp[i][n];
if(ans<0.005)
printf("Impossible\n");
else
printf("%.2lf\n",ans);
}
int main(){
read();
return 0;
}