1. 程式人生 > >dtoj#4120. 飛行棋(feixingqi)

dtoj#4120. 飛行棋(feixingqi)

print style eve 6.0 有一個 成功 標簽 std define

題目描述:

小G在玩飛行棋。這個飛行棋與一般的飛行棋相比,規則要簡單得多。棋盤上一共有從左到右n個格子,按1到n標號。m個玩家各持有一個棋子。棋子第一個到達第n格的玩家勝利。每個玩家輪流投擲6面的骰子,投出幾點就把自己的棋子往右移動幾步。當棋子被移動到某些格子時,棋子會被傳送到其他格子。如果棋子被移動到第i格,若ai=i ,則棋子仍然在第i格;否則棋子會被傳送到第ai格。棋子每次按骰子投出的數字移動時,是一次性移動了若幹格,即棋子不會在中途被傳送走,只可能在移動完後被傳送走。不同玩家的棋子之間互不影響。

現在小G告訴了你m個玩家棋子所在位置。現在開始按1號玩家到m號玩家的順序依次扔骰子。小G想知道每個玩家獲勝的概率。

算法標簽:DP

思路:

因為其具有收斂性,所以當你局數足夠多時,近似於得到答案。

令狀態表示f[i][j]表示初始位置在j經過i局恰好到n的概率。依此枚舉在某一輪我成功了其余都在我之後成功過的概率,得到答案。

以下代碼:

技術分享圖片
#include<bits/stdc++.h>
#define il inline
#define db double
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const db P=1.0/6.0;
const int N=170,M=550000;
int
n,m,a[N],p[22],op; db f[2][N],g1[M+2][22],g2[M+2][22],g[M+2][22]; il int read(){ int x,f=1;char ch; _(!)ch==-?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } int main() { n=read();m=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=n+1
;i<=n+6;i++)a[i]=n; for(int i=1;i<=m;i++)p[i]=read(); if(m==1){puts("1.000000");return 0;} f[0][n]=1.0; for(int i=1;i<=M;i++){ op^=1; for(int j=1;j<=n;j++)f[op][j]=0; for(int j=1;j<n;j++){ for(int k=1;k<=6;k++) f[op][j]+=f[op^1][a[j+k]]*P; } for(int j=1;j<=m;j++)g[i][j]+=f[op][p[j]]; } for(int i=M;i;i--)for(int j=1;j<=m;j++)g[i][j]+=g[i+1][j]; for(int i=1;i<=M;i++){ g1[i][0]=g2[i][m+1]=1.0; for(int j=1;j<=m;j++)g1[i][j]=g1[i][j-1]*g[i][j]; for(int j=m;j;j--)g2[i][j]=g2[i][j+1]*g[i][j]; } for(int i=1;i<=m;i++){ db ans=0; for(int j=1;j<=M;j++){ ans+=g1[j+1][i-1]*g2[j][i+1]*(g[j][i]-g[j+1][i]); } printf("%lf\n",ans); } return 0; }
View Code

dtoj#4120. 飛行棋(feixingqi)