BZOJ 3143 [Hnoi2013]游走 ——概率DP
概率DP+高斯消元
与博物馆一题不同的是,最终的状态是有一定的概率到达的,但是由于不能从最终状态中出来,所以最后要把最终状态的概率置为0。
一条边$(x,y)$经过的概率是x点的概率$*x$到$y$的概率+$y$的概率$*y$到$x$的概率。
然后直接高斯消元即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define maxn 500005 double a[505][505],p[500005]; int h[maxn],fr[maxn],to[maxn],ne[maxn],en=0,n,m,du[maxn]; void add(int a,int b) {to[en]=b;fr[en]=a;ne[en]=h[a];h[a]=en++;} void solve(int x) { a[x][x]=1; if (x==n) return; for (int i=h[x];i>=0;i=ne[i]) { if (to[i]==n) continue; a[x][to[i]]-=1.0/du[to[i]]; } } void gauss() { F(i,1,n) { int tmp=i; while (!a[tmp][i]&&tmp<=n) tmp++; if (tmp>n) continue; F(j,i,n+1) swap(a[i][j],a[tmp][j]); F(j,1,n) if (j!=i) { double t=a[j][i]/a[i][i]; F(k,1,n+1) a[j][k]-=t*a[i][k]; } } } int main() { memset(h,-1,sizeof h); scanf("%d%d",&n,&m); F(i,1,m) { int a,b; scanf("%d%d",&a,&b); add(a,b);add(b,a); du[a]++;du[b]++; } F(i,1,n) solve(i); a[1][n+1]=1; gauss(); F(i,1,n) a[i][i]=a[i][n+1]/a[i][i]; int tot=0; for (int i=0;i<en;i+=2) p[++tot]=a[fr[i]][fr[i]]/(du[fr[i]]*1.0)+a[to[i]][to[i]]/(du[to[i]]*1.0); sort(p+1,p+tot+1); double ans=0; F(i,1,tot) ans+=p[i]*(m-i+1); printf("%.3f\n",ans); }