Description:
一个无向连通图,顶点从
1
编号到
Solution:
如果我们求出了每条边经过次数的期望值,然后我们就可以按期望值贪心了。所以重点在于求期望值。
对于每条边我们可以拆成两条有向边,那么有:
E(u,v)=∑(p,u)∈边集E(p,u)deg(u)+[u==1]deg(u)
我们可以高斯消元,但是时间复杂度是
O(N6)
的。但是显然会
TLE
我们考虑到达每个点的次数的数学期望值,则有: E(x)=(∑(x,y)∈边集,y≠N)+[x==1],E(N)=0
所以每条边的数学期望值:
E(u,v)=E(u)deg(u)+E(v)deg(v)
时间复杂度
O(N3)
Code:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
int N,M;
struct bian_
{
int st;
int to;
double val;
}bian[250010]={{0,0,0}};
int du[510]={0};
double A[510]={0};
double fc[510][510]={{0}};
bool dcmp(double x)
{return fabs(x)<1e-10;}
void Gauss()
{
for(int i=1;i<=N-1;i++)
{
int g=0;
for(int j=i;j<=N-1;j++)
{
if(dcmp(fc[j][i])==false)
{
g=j;
break;
}
}
if(g==0) continue;
swap(fc[g],fc[i]);
for(int j=1;j<=N-1;j++)
if(j!=i && dcmp(fc[j][i])==false)
{
double o=fc[j][i]/fc[i][i];
for(int p=0;p<=N-1;p++)
fc[j][p]-=fc[i][p]*o;
}
}
for(int i=1;i<N;i++)
A[i]=fc[i][0]/fc[i][i];
return;
}
bool cmp(struct bian_ a1,struct bian_ a2)
{return a1.val>a2.val;}
int main()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
scanf("%d%d",&bian[i].st,&bian[i].to);
du[bian[i].st]++,du[bian[i].to]++;
}
for(int i=1;i<=M;i++)
{
if(bian[i].to==N || bian[i].st==N) continue;
fc[bian[i].st][bian[i].to]=-(double)1/du[bian[i].to];
fc[bian[i].to][bian[i].st]=-(double)1/du[bian[i].st];
}
for(int i=1;i<N;i++)
fc[i][i]=1,fc[i][0]=(i==1);
Gauss();
for(int i=1;i<=M;i++)
bian[i].val=A[bian[i].st]/du[bian[i].st]+A[bian[i].to]/du[bian[i].to];
sort(bian+1,bian+M+1,cmp);
double ans=0;
for(int i=1;i<=M;i++)
ans+=bian[i].val*i;
printf("%.3lf",ans);
return 0;
}