bzoj3143: [Hnoi2013]游走

http://www.lydsy.com/JudgeOnline/problem.php?id=3143

计算每条边经过的概率e[]

然后经过概率多的分配的编号大,经过概率少的分配的编号小

如何计算边经过的概率?

假设我们知道点的经过的概率p[]

若边i连接u和v,那么e[i]=p[u]/d[u]+p[v]/d[v]

d表示点的度数

如何计算点的经过概率?

dp[i]=Σ dp[j]/d[j]

高斯消元求解

注意到达终点就不能再走了,所以高斯消元的系数中不涉及和终点有关的信息

注意起点1的方程是 dp[1]=1+Σ dp[j]/d[j]

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 503

int tot;
int front[N],to[N*N*2],nxt[N*N*2],from[N*N*2];

double d[N];

double a[N][N];

double e[N*N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v;
}

void gauss(int n)
{
    int r; double t;
    for(int i=1;i<n;++i)
    {
        r=i;
        for(int j=i+1;j<n;++j)
            if(fabs(a[j][i])>fabs(a[r][i])) r=j;
        if(r!=i) 
            for(int j=1;j<=n;++j) swap(a[i][j],a[r][j]);
        for(int k=i+1;k<n;++k)
        {
            t=a[k][i]/a[i][i];
            for(int j=i;j<=n;++j) a[k][j]-=t*a[i][j];
        }
    }
    for(int i=n-1;i;--i)
    {
        for(int j=i+1;j<n;++j) a[i][n]-=a[i][j]*a[j][n];
        a[i][n]/=a[i][i];
    }
}

int main()
{
    int n,m;
    read(n); read(m);
    int u,v;
    for(int i=1;i<=m;++i) 
    {
        read(u); read(v);
        add(u,v);
        d[u]++; d[v]++;
    }
    for(int i=1;i<n;++i)
    {
        a[i][i]=1;
        for(int j=front[i];j;j=nxt[j])
            if(to[j]!=n) a[i][to[j]]-=1/d[to[j]];
    }
    a[1][n]=1;
    gauss(n);
    int cnt=0;
    for(int i=1;i<=tot;i+=2) e[++cnt]=a[from[i]][n]/d[from[i]]+a[to[i]][n]/d[to[i]];
    sort(e+1,e+m+1,greater<double>());
    double ans=0;
    for(int i=1;i<=m;++i) ans+=e[i]*i;
    printf("%.3lf",ans);
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8604469.html