【HDU】4418 Time travel
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天才搞完?(妈妈呀,这效率太低了啊.
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。