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);
}

  

  

posted @ 2017-03-30 16:04  SfailSth  阅读(297)  评论(0编辑  收藏  举报