http://acm.hdu.edu.cn/showproblem.php?pid=4418
读了一遍题后大体明白意思,但有些细节不太确定。就是当它处在i点处,它有1~m步可以走,但他走的方向不确定呢。后来想想这个方向是确定的,就是他走到i点的方向,它会继续朝着这个方向走,直到转向回头。
首先要解决的一个问题是处在i点处,它下一步该到哪个点。为了解决方向不确定的问题,将n个点转化为2*(n-1)个点。例如当n=4时由原来的0123变为012321,它对应的编号为012345,这样就不用管它哪个方向,统一处理了,当向前走k步时即(i+k)%n。
然后设出dp[i]表示在i点处时到达终点的期望步数,那么可列出转移方程dp[i] = ∑( pk * (dp[ (x+k)%n ] +k) )。但是有些点是永远无法到达的,因此先bfs出所有到达的点,然后列出方程组解方程。
有许多注意的点,判断p[i]是否为0等。
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL __int64
#define LL long long
#define eps 1e-9
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 210;
double p[maxn];
double a[maxn][maxn];//增广矩阵
double X[maxn];//解集
int num[maxn];//给每个能给到达的point离散化
int n,m,x,y,d;
int equ,var,cnt;
bool Gauss()
{
int row,col,max_r,i,j;
row = 0;
col = 0;
while(row < equ && col < var)
{
max_r = row;
for(i = row+1; i < equ; i++)
{
if(fabs(a[i][col]) > fabs(a[max_r][col]))
max_r = i;
}
if(max_r != row)
{
for(j = col; j <= var; j++)
swap(a[row][j], a[max_r][j]);
}
if(fabs(a[row][col]) < eps)
{
col++;
continue;
}
for(i = row+1; i < equ; i++)
{
if(fabs(a[i][col]) < eps) continue;
double t = a[i][col]/a[row][col];
a[i][col] = 0.0;
for(j = col+1; j <= var; j++)
a[i][j] -= a[row][j]*t;
}
row++;
col++;
}
for(i = row; i < equ; i++)
if(fabs(a[i][var]) > eps)
return false; //无解
for(i = equ-1; i >= 0; i--)
{
if(fabs(a[i][i]) < eps) continue;
double t = a[i][var];
for(j = i+1; j < var; j++)
t -= a[i][j]*X[j];
X[i] = t/a[i][i];
}
return true;
}
void bfs(int s) //bfs找出所有能够到达的点并离散化
{
queue <int> que;
que.push(s);
num[s] = cnt++;
while(!que.empty())
{
int u = que.front();
que.pop();
for(int i = 1; i <= m; i++)
{
if(fabs(p[i]) < eps)
continue;
int v = (u+i)%n;
if(num[v] == -1)
{
num[v] = cnt++;
que.push(v);
}
}
}
}
int main()
{
int test;
scanf("%d",&test);
for(int item = 1; item <= test; item++)
{
scanf("%d %d %d %d %d",&n,&m,&y,&x,&d);
for(int i = 1; i <= m; i++)
{
scanf("%lf",&p[i]);
p[i] /= 100;
}
if(x == y)
{
printf("0.00\n");
continue;
}
n = 2*(n-1);
if(d == 1)
x = n-x;
memset(num,-1,sizeof(num));
cnt = 0;
bfs(x);
if(num[y] == -1 && num[n-y] == -1) //注意这里是 &&,只有当两个方向都走不到才算走不到
{
printf("Impossible !\n");
continue;
}
memset(a,0,sizeof(a));
memset(X,0,sizeof(X));
equ = var = cnt;
for(int i = 0; i < n; i++)
{
if(num[i] != -1)
{
if(i == y || i == n-y) //注意特判终点
{
a[num[i]][num[i]] = 1;
a[num[i]][cnt] = 0;
continue;
}
a[num[i]][num[i]] = 1;
for(int j = 1; j <= m; j++)
{
int t = (i+j)%n;
if(num[t] != -1)
a[num[i]][num[t]] -= p[j];
a[num[i]][cnt] += j*p[j];
}
}
}
if(Gauss())
printf("%.2lf\n",X[num[x]]);
else printf("Impossible !\n");
}
return 0;
}