首页 > 代码库 > HDU 4418 高斯消元法求概率DP

HDU 4418 高斯消元法求概率DP

把两种状态化成2*n-2的一条线上的一种状态即可。很容易想到。

高斯列主元法,不知为什么WA。要上课了,不玩了。。。逃了一次课呢。。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>using namespace std;double const eps=1e-8;double G[210][210];int n,m,s,e,d; double sum;double pk[110];double ans[210];bool find(int i){	int k=i;	for(int j=i+1;j<n;j++){		if(fabs(G[j][i])>fabs(G[k][i]))		k=j;	}	if(fabs(G[k][i])<eps) return false;	for(int p=i;p<=n;p++)	swap(G[i][p],G[k][p]);	return true;}bool Guass(){	for(int i=0;i<n;i++){		if(find(i)){			for(int j=i+1;j<n;j++){				double k=G[j][i]/G[i][i];				for(int p=i;p<=n;p++)				G[j][p]=G[j][p]-k*G[i][p];			}		}		else return false;	}		ans[n-1]=G[n-1][n]/G[n-1][n-1];	for(int i=n-2;i>=0;i--){		double sum=0;		for(int j=n-1;j>i;j--){			sum+=(G[i][j]*ans[j]);		}		ans[i]=(G[i][n]-sum)/G[i][i];	}	return true;}int main(){	int T;	scanf("%d",&T);	while(T--){		scanf("%d%d%d%d%d",&n,&m,&e,&s,&d);		sum=0;		n=2*n-2;		for(int i=1;i<=m;i++){			scanf("%lf",&pk[i]);			pk[i]/=100;			sum+=(i*pk[i]);		}		if (s == e){               puts ("0.00");               continue;           } 		if(d==0) s=s;		else if(d==1) s=(n-s)%n;		memset(G,0,sizeof(G));		for(int i=0;i<n;i++){			G[i][i]=-1;			if(i==e||i==n-e) continue;			for(int j=1;j<=m;j++){				G[i][(j+i)%n]=pk[j];			}			G[i][n]=-sum;		}		if(!Guass()){			puts("Impossible !");   		}		else{			if(ans[s]<eps) puts("Impossible !");			else			printf("%.2f\n",ans[s]);		}	}	return 0;}

  这个是别人的

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <queue>#include <algorithm>#include <math.h>using namespace std;#define M 205#define eps 1e-8int equ, var;double a[M][M], x[M];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 (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;}//has[x]表示人在x点时的变量号,因为我们只用可达状态建立方程,所以需要编号int has[M], vis[M], k, e, n, m;double p[M], sum;int bfs (int u){	memset (has, -1, sizeof(has));	memset (a, 0, sizeof(a));			//忘记初始化WA勒,以后得注意	memset (vis, 0, sizeof(vis));	int v, i, flg = 0;	queue<int> q;	q.push (u);	k = 0;	has[u] = k++;	while (!q.empty ())	{		u = q.front ();		q.pop ();		if (vis[u]) continue;		vis[u] = 1;		if (u == e || u == n-e)		//终点有两个,你懂的~		{			a[has[u]][has[u]] = 1;			x[has[u]] = 0;			flg = 1;			continue;		}		//E[x] = sum ((E[x+i]+i) * p[i])		// ----> E[x] - sum(p[i]*E[x+i]) = sum(i*p[i])		a[has[u]][has[u]] = 1;		x[has[u]] = sum;		for (i = 1; i <= m; i++)		{			//非常重要!概率为0,该状态可能无法到达,如果还去访问并建立方程会导致无解			if (fabs (p[i]) < eps) continue;			v = (u + i) % n;			if (has[v] == -1) has[v] = k++;			a[has[u]][has[v]] -= p[i];			q.push (v);		}	}	return flg;}int main(){	int t, s, d, i;	scanf ("%d", &t);	while (t--)	{		scanf ("%d%d%d%d%d", &n, &m, &e, &s, &d);		n = 2*(n-1);		sum = 0;		for (i = 1; i <= m; i++)		{			scanf ("%lf", p+i);			p[i] = p[i] / 100;			sum += p[i] * i;		}		if (s == e)		{			puts ("0.00");			continue;		}		//一开始向左,起点要变		if (d > 0) s = (n - s) % n;		if (!bfs (s))		{			puts ("Impossible !");			continue;		}		equ = var = k;		Gauss ();		printf ("%.2f\n", x[has[s]]);	}    return 0;}

  

HDU 4418 高斯消元法求概率DP