【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天才搞完?(妈妈呀,这效率太低了啊.

 

你可能感兴趣的:(time)