您的位置:首页 > 其它

HDU 4418 Time travel(高斯消元+概率DP)

2015-09-15 20:34 239 查看

题意:一个人在数轴上来回走,以pi的概率走i步i∈[1, m],给定n(数轴长度),m,e(终点),s(起点),d(方向),求从s走到e经过的点数期望。

思路:先把n(n>1)个点展开成2*n-2个点,这一步的作用是简化方向这个状态,使得现在所有点在一条直线上,例如原来是01234321,现在展开成了01234567.

设dp[i]为当前在i点走到目标点的期望步数,根据状态转移可以得到若干方程

但是,这些方程里有些是不合法的,所以会导致结果错误,

这是因为,对于一个点来说,可能从起点走不到这个点,但是方程组里我们还是保留了这些方程,这样的话结果计算出来就会错误,所以在开始时我们可以一次bfs将所有能到达的点标记并重新编号,然后计算这些点的状态转移方程。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-9
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
int n, m, Y, X, d;
const int MAXN=220;
double p[MAXN];
double a[MAXN][MAXN],x[MAXN];//方程的左边的矩阵和等式右边的值,求解之后x存的就是结果,行列编号从0开始 
int equ,var;//方程数和未知数个数
int num[MAXN];
int Gauss() {
    int i,j,k,col,max_r;
    for(k=0,col=0;k<equ&&col<var;k++,col++) {
        max_r=k;
        for(i=k+1;i<equ;i++)
          if(fabs(a[i][col])>fabs(a[max_r][col]))
            max_r=i;
        if(fabs(a[max_r][col])<eps)return 0;
        if(k!=max_r) {
            for(j=col;j<var;j++)
              swap(a[k][j],a[max_r][j]);
            swap(x[k],x[max_r]);
        }
        x[k]/=a[k][col];
        for(j=col+1;j<var;j++)a[k][j]/=a[k][col];
        a[k][col]=1;
        for(i=0;i<equ;i++)
          if(i!=k) {
              x[i]-=x[k]*a[i][k];
              for(j=col+1;j<var;j++)a[i][j]-=a[k][j]*a[i][col];
              a[i][col]=0;
          }
    }
    return 1;
}
int bfs() {
	queue<int> q;
	q.push(X);
	int cnt = 0;
	memset(num, -1, sizeof(num));
	num[X] = cnt++;
	while(!q.empty()) {
		int t = q.front(); q.pop();
		for(int i = 1; i <= m; i++) {
			if(fabs(p[i]) < eps) continue;
			int id = (t+i)%n;
			if(num[id] == -1) {
				num[id] = cnt++;
				q.push(id);
			}
		} 
	}
	return cnt;
} 
int main() {
    //freopen("input.txt", "r", stdin);
	int T; cin >> T;
	while(T--) {
		int tmp;
		scanf("%d%d%d%d%d", &tmp, &m, &Y, &X, &d);
		for(int i = 1; i <= m; i++) scanf("%lf", &p[i]), p[i]/=100;
		n = 2*tmp - 2;
		if(!n) n+=1;
		if(d>0) X = n - X;
		equ = var = bfs();
		if(num[Y]==-1 && num[n-Y]==-1) { 
			printf("Impossible !\n");
			continue;
		}
		memset(x, 0, sizeof(x));
		memset(a, 0, sizeof(a));
		for(int i = 0; i < n; i++) {
			if(num[i]==-1) continue;
			a[num[i]][num[i]] = 1.0;
			if(i==Y || i==n-Y) continue;
			for(int j = 1; j <= m; j++) {
				int id = (i+j) % n;
				if(num[id] != -1) {
					a[num[i]][num[id]] -= p[j];
					x[num[i]] += j*p[j];
				}
			}	
		}
		if(Gauss()) printf("%.2f\n", x[num[X]]);
		else printf("Impossible !\n");	
	}
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: