HDU 4418 高斯消元法求概率DP
把两种状态化成2*n-2的一条线上的一种状态即可。很容易想到。
高斯列主元法,不知为什么WA。要上课了,不玩了。。。逃了一次课呢。。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <queue> 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 vis[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; } bool BFS(int s){ queue<int>q; q.push(s); memset(vis,false,sizeof(vis)); vis[s]=true; while(!q.empty()){ int te=q.front(); q.pop(); for(int i=1;i<=m;i++){ if(pk[i]<eps) continue; int u=(te+i)%n; if(!vis[u]){ vis[u]=true; q.push(u); if(u==e||u==n-e) return true; } } } return false; } 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++){ if(pk[j]<eps) G[i][(j+i)%n]=pk[j]; } G[i][n]=-sum; } if(!BFS(s)){ puts("Impossible !"); continue; } if(!Guass()){ 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-8 int 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; }