第一次做这类题目,我还是太弱了。
首先贪心思想,期望小的赋大权值,期望大的赋小权值,所以关键是求边的期望。设边i的期望为 wi ,点i的期望为 xi ,点i的度数为 di ,则 wi=(u,v) 的期望 wi=xudu+xvdv
那么对于某个点的期望 xi 怎么求呢。
xi=∑j , exist(i,j)in Exj
然后存在两个特殊的点,即 1 和 n 。
由于1号点一定会经过,则
x1=∑j , exist(1,j)in Exj
由于 n 号点到达后不会出现,所以 n 号点对其他点没有贡献,所以
xn=1
那么就得到了 n−1 个方程,高斯消元解一下,最后算出边的期望然后贪心。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define eps 1e-9
using namespace std;
double a[505][505],w[505];
int d[505],head[505],list[500005],next[500005];
int n,m,cnt;
struct node {int x,y;} e[250005];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void insert(int x,int y)
{
d[y]++;
next[++cnt]=head[x];
head[x]=cnt;
list[cnt]=y;
}
inline void gauss()
{
int y;
for (int i=1;i<=n;i++)
{
for (y=i;y<=n;y++)
if (fabs(a[y][i])>eps) break;
if (y>n) continue;
if (y!=i)
for (int j=1;j<=n+1;j++) swap(a[y][j],a[i][j]);
double t=a[i][i];
for (int j=1;j<=n+1;j++) a[i][j]/=t;
for (int j=1;j<=n;j++)
if (j!=i)
{
double t=a[j][i];
for (int k=1;k<=n+1;k++)
a[j][k]-=t*a[i][k];
}
}
}
int main()
{
// freopen("walk.in","r",stdin);
// freopen("walk.out","w",stdout);
n=read(); m=read();
for (int i=1;i<=m;i++)
{
e[i].x=read(); e[i].y=read();
insert(e[i].x,e[i].y);
if (e[i].x==e[i].y) continue;
insert(e[i].y,e[i].x);
}
for (int i=1;i<=n-1;i++)
{
a[i][i]=1;
for (int j=head[i];j;j=next[j])
{
if (list[j]==n) continue;
a[i][list[j]]-=1.0/d[list[j]];
}
}
a[1][n]=1;
n--;
gauss();
for (int i=1;i<=m;i++)
w[i]=a[e[i].x][n+1]/(d[e[i].x]*1.0)+a[e[i].y][n+1]/(d[e[i].y]*1.0);
sort(w+1,w+m+1);
double ans=0;
for (int i=1;i<=m;i++) ans+=w[i]*(m-i+1);
printf("%.3lf\n",ans);
return 0;
}