转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:有一个地图,一个人从某个点出发,问走到花园的期望步数为多少
http://acm.hdu.edu.cn/showproblem.php?pid=2262
基础的高斯求概率。
设某点的期望步数为Ei。
那么目标的Ei=0。
Ei=(Enext1+Enext2……Enextk)/k+1。
整理下就是Enext1+Enext2……Enextk-k*Ei=-k
根据i点的后继结点nextj,那么从所有的后继结点走一步都可以到达i点。便是所有后继的期望平均值+1.
以此建立方程组,然后用高斯消元求解。
以下几个地方需要注意:
1、后继必须是可达目标的,这一点可以在搜索得到,所有的可达点,不是可达的不能计入
2、这题有多个出口,在搜索的时候需要注意,可以dfs,bfs,floodfill
3、让我纠结的高斯,我写的太shi了,而且没有通用性。注意精度
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<cmath> #define LL long long #define MOD 1000000007 #define eps 1e-6 #define zero(a) fabs(a)<eps using namespace std; int n,m; int way[4][2]={0,1,0,-1,1,0,-1,0}; char str[20][20]; double a[230][230]; bool flag[20][20]; int ans; //搜索预处理一下 bool bfs(){ int s,e; memset(flag,false,sizeof(flag)); queue<int>x,y; while(!x.empty()) x.pop(); while(!y.empty()) y.pop(); for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(str[i][j]=='$'){ x.push(i); y.push(j); s=i; e=j; flag[i][j]=true; } while(!x.empty()){ int ux=x.front(),uy=y.front(),vx,vy; x.pop();y.pop(); for(int i=0;i<4;i++){ vx=ux+way[i][0]; vy=uy+way[i][1]; if(vx>=0&&vx<n&&vy>=0&&vy<m&&str[vx][vy]!='#'&&!flag[vx][vy]){ flag[vx][vy]=true; x.push(vx);y.push(vy); } } } return false; } //高斯,写得太shi了 bool gauss(int n){ int i,j; for(i=0,j=0;i<n&&j<n;j++){ int k; for(k=i;k<n;k++) if(!zero(a[k][j])) break; if(k<n){ if(i!=k) for(int r=j;r<=n;r++) swap(a[i][r],a[k][r]); if(idx==k) idx=i; double tt=1/a[i][j]; for(int r=j;r<=n;r++) a[i][r]*=tt; for(int r=0;r<n;r++) if(r!=i){ for(int t=n;t>=j;t--) a[r][t]-=a[r][j]*a[i][t]; } i++; } } for(int r=i;r<n;r++) if(!zero(a[r][n])) return false; return true; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ for(int i=0;i<n;i++) scanf("%s",str[i]); for(int i=0;i<=n*m;i++) for(int j=0;j<=n*m;j++) a[i][j]=0; bfs(); int s,e; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ int cnt=0; if(str[i][j]=='@'){ s=i; e=j; } //目标的方程便是e[i]=0; if(str[i][j]=='$'){ a[i*m+j][n*m]=0; a[i*m+j][i*m+j]=1; continue; } //不可达的点可以忽略 if(str[i][j]=='#') continue; for(int k=0;k<4;k++){ int x=i+way[k][0]; int y=j+way[k][1]; if(x>=0&&x<n&&y>=0&&y<m&&str[x][y]!='#'&&flag[x][y]){ a[i*m+j][x*m+y]=1; cnt++; } } a[i*m+j][n*m]=-1*cnt; a[i*m+j][i*m+j]=-1*cnt; } if(flag[s][e]&&gauss(n*m)){ for(int i=0;i<n*m;i++) if(zero(a[i][s*m+e]-1)){ printf("%.6f\n",a[i][n*m]); break; } } else puts("-1"); } return 0; }