zoukankan      html  css  js  c++  java
  • 【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
    ", 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天才搞完?(妈妈呀,这效率太低了啊.

  • 相关阅读:
    BZOJ 1066 [SCOI2007]蜥蜴 (最大流)
    Codeforces 1092 D2 Great Vova Wall (Version 2) (栈)
    BZOJ 1046 [HAOI2007]上升序列(LIS + 贪心)
    牛客练习赛34 D little w and Exchange(归纳)
    BZOJ 1042 [HAOI2008]硬币购物(完全背包+容斥)
    GTMD并查集!
    2018icpc南京现场赛-G Pyramid(打标找规律+逆元)
    drwxr-xr-x 2 root root 4096 06-29 14:30 Test 分段解释
    Linux里面非常重要的目录
    点击 触发 事件 的 jQuery 写法样式
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4302522.html
Copyright © 2011-2022 走看看