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