【HDU】4418 Time travel

时间:2024-10-19 22:35:20

http://acm.hdu.edu.cn/showproblem.php?pid=4418

题意:一个0~n-1的坐标轴,给出起点X、终点Y,和初始方向D(0表示从左向右、1表示从右向左,-1表示起点或终点),在走的过程中如果到达起点或终点,那么下一步往反方向走。每次可以走1~m步,每步概率为p[i],问走到终点的期望步数。(n,m,X,Y<=100)

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=205;
const double eps=1e-6;
double A[N][N], p[N], C;
inline double abs(double x) { return x<0?-x:x; } int guass(int n, int m) {
int x=1, y=1;
while(x<=n && y<=m) {
int pos=x;
for(int i=x+1; i<=n; ++i) if(abs(A[i][y])>abs(A[pos][y])) pos=i;
if(abs(A[pos][y])<eps) { ++y; continue; }
for(int i=1; i<=m+1; ++i) swap(A[x][i], A[pos][i]);
for(int i=x+1; i<=n; ++i) if(abs(A[i][y])>=eps) {
double t=A[i][y]/A[x][y];
for(int j=y; j<=m+1; ++j) A[i][j]-=t*A[x][j];
}
++x; ++y;
}
for(int i=x; i<=n; ++i) if(abs(A[i][m+1])>=eps) return 0;
for(int i=m; i; --i) if(abs(A[i][i])>=eps) {
for(int j=i+1; j<=m; ++j) A[i][m+1]-=A[j][m+1]*A[i][j];
A[i][m+1]/=A[i][i];
}
return 1;
}
bool vis[N];
int n, m, X, Y, D, all;
void get(int now, double a[]) {
if(!vis[now]) { a[now]=1; return; }
int fx=1, x=now;
if(x>n) fx=-1;
for(int i=1; i<=m; ++i) {
if(x==n) { fx=-1; x=all; }
else if(x==n+1) { fx=1; x=1; }
x+=fx;
a[x]+=p[i];
}
a[now]-=1;
a[all+1]=-C;
}
void bfs() {
static int q[N], front, tail, x, fx;
memset(vis, 0, sizeof(bool)*(all+1));
front=tail=0; q[tail++]=X+D*n;
while(front!=tail) {
x=q[front++]; if(front==N) front=0;
fx=1;
if(x>n) fx=-1;
for(int i=1; i<=m; ++i) {
if(x==n) { fx=-1; x=all; }
else if(x==n+1) { fx=1; x=1; }
x+=fx;
if(!vis[x] && abs(p[i])>=eps) { vis[x]=1; q[tail++]=x; if(tail==N) tail=0; }
}
}
vis[1]=vis[all]=vis[Y]=vis[Y+n]=0;
}
int main() {
int T; scanf("%d", &T);
while(T--) {
scanf("%d%d%d%d%d", &n, &m, &Y, &X, &D); ++X; ++Y;
C=0;
for(int i=1; i<=m; ++i) scanf("%lf", &p[i]), p[i]/=100, C+=p[i]*i;
if(X==Y) { puts("0.00"); continue; }
if(D==-1) { if(X==1) D=1; else D=0; }
all=n<<1;
bfs();
for(int i=1; i<=all; ++i) { memset(A[i], 0, sizeof(double)*(all+2)); get(i, A[i]); }
if(guass(all, all)) {
if(abs(A[X+D*n][all+1])<eps) puts("Impossible !");
else printf("%.2f\n", A[X+D*n][all+1]);
}
else puts("Impossible !");
}
return 0;
}

  

这题我是调得憔悴啊QAQ

1、首先一开始我并没有想到有非法状态(即转移不到的状态我照样让他进了高斯中的矩阵中QAQ)

2、D=-1的条件漏看了啊,导致我sb的提交了20+次然后每次都是RE QAQ 妈妈呀...

首先方程和高斯消元比较显然..

设$d[i]$表示从$i$走到达终点所需要的步数:

$$d[i]=\sum_{k=1}^{m} p[k](d[转移到k步后]+k)$$

变换一下变成:

$$\sum_{k=1}^{m} p[k]d[转移到k步后] - d[i] = -\sum_{k=1}^{m} p[k]*k$$

发现这和方向其实是有关的,那么我们可以变成两个状态:

$1<=i<=n$,$d[i]$表示从左向右,$d[i+n]$表示从右向左。判断一些非法状态即可

可是这样是有问题的,在某些情况下可能某个$i$没有合法被访问过,那么就要bfs一次....(因为概率为0的时候是不会访问的啊QAQ所以不要放入合法状态中...)

(至此概率期望dp完结撒花(咦为什么我做了12天才搞完?(妈妈呀,这效率太低了啊.