很普通的概率DP的一道题
题意大概是:K要通过时间传送机从X到达Y抓捕犯人,一共n个时间点,每次传送有可能经过m(<m)个时间点才会停下来,并且移动方向有一定规律如0123210……
那么很明显,我们可以将每个点按照方向进行拆分,为什么会想到这一点呢?因为对于每一个点,从左边到达该点的期望和从右边到达该点的期望一般是不相同的(除了端点,因为它没办法从另一边到达该点),因此就把所有点整合为2*n-2个,设dp[x]为到达x时间点的期望个数,那么dp[x]=Σ(dp[x-i]+i)*p[i](1<=i<=m)。再高斯消元就可以得到了。其中还有一点问题,就是m的值有可能大于n的值的,即同一个方程可能出现两次同一未知量,在下面的代码中会有所体现
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int SIZEN=205;
const double eps=1e-8;
double p[SIZEN];
double dp[SIZEN][SIZEN];
int sum,cnt,Hash[SIZEN];
int m,n,x,y,d;
double tt;
void init(){
memset(Hash,-1,sizeof(Hash));
memset(dp,0,sizeof(dp));
tt=0;
sum=2*n-2;
}
void guass(){
int i,j,r,c;
for(r=c=0;r<sum&&c<sum;r++,c++){
for(i=r;i<sum;i++)
if(dp[i][c]!=0) break;
if(i==sum) break;
if(i!=r) for(j=c;j<=sum;j++) swap(dp[i][j],dp[r][j]);
for(i=r+1;i<sum;i++){
if(dp[i][c]!=0){
double tmp=dp[i][c]/dp[r][c];
for(j=c;j<=sum;j++) dp[i][j]-=dp[r][j]*tmp;
}
}
}
for(i=sum-1;i>=0;i--){
dp[i][sum]/=dp[i][i];
dp[i][i]=1;
for(j=i-1;j>=0;j--)
dp[j][sum]-=dp[j][i]*dp[i][sum];
}
}
bool zero(double a){
return fabs(a)<eps;
}
int bfs(int s){
cnt=0;
int flag=0;
int vis[SIZEN];
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
Hash[s]=cnt++;
while(!q.empty()){
int u=q.front();q.pop();
if(vis[u]) continue;
vis[u]=1;
if(u==y||u==sum-y){
dp[Hash[u]][Hash[u]]=1;
dp[Hash[u]][sum]=0;
flag=1;
continue;
}
dp[Hash[u]][Hash[u]]=1;
for(int i=1;i<=m;i++){
if(zero(p[i])) continue;
int v=(u+i)%sum;
if(Hash[v]==-1) Hash[v]=cnt++;
dp[Hash[u]][Hash[v]]-=p[i];//如果为dp[Hash[u]][Hash[v]]=-p[i];就会出错
dp[Hash[u]][sum]+=p[i]*i;
q.push(v);
}
}
return flag;
}
void debug(){
int i,j;
for(i=0;i<sum;i++){
for(j=0;j<=sum;j++) printf("%6.2lf",dp[i][j]);
printf("\n");
}
}
int main()
{
//freopen("data.in","r",stdin);
int i,j,_;
scanf("%d",&_);
while(_--){
scanf("%d%d%d%d%d",&n,&m,&y,&x,&d);
init();
for(i=1;i<=m;i++){
scanf("%lf",&p[i]);
p[i]/=100;
}
if(x==y) {printf("0.00\n");continue;}
if(d) x=(sum-x)%sum;
if(!bfs(x)){
printf("Impossible !\n");
continue;
}
for(i=0;i<sum;i++) swap(dp[i][cnt],dp[i][sum]);
sum=cnt;
guass();
printf("%.2f\n",dp[Hash[x]][sum]);
}
return 0;
}