正题
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=3143
https://www.luogu.org/problem/P3232
题目大意
一张无向图nnn个点mmm条边,然后给每条边附上1∼m1\sim m1∼m的权值(不能重复),求1走到nnn的最小期望值。
解题思路
我们可以计算出每条边经过的期望次数,在此之前我们要先计算出每个点经过的期望次数。
我们发现很容易列出方程fx=∑y−>xfyinxf_x=\sum_{y->x} \frac{f_y}{in_x}fx=y−>x∑inxfy
但是我们发现该方程有后效性所以我们用高斯消元求解。
然后对于一条边(x,y)(x,y)(x,y)经过的期望次数就是
fxinx+fyiny\frac{f_x}{in_x}+\frac{f_y}{in_y}inxfx+inyfy
然后贪心选取边权即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=510;
int n,m,x[N*N],y[N*N],in[N];
double a[N][N],q[N*N],ans;
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d",&x[i],&y[i]);a[x[i]][y[i]]=a[y[i]][x[i]]=1;in[y[i]]++;in[x[i]]++;}memset(a[n],0,sizeof(a[n]));for(int i=1;i<n;i++){for(int j=1;j<n;j++)a[i][j]=-a[i][j]/in[j];a[i][n]=0;a[i][i]=1;}a[1][n]=1;for(int i=1;i<n;i++){int z=i;for(int j=i+1;j<n;j++)if(fabs(a[j][i])>fabs(a[z][i])) z=j;for(int j=1;j<=n;j++)swap(a[i][j],a[z][j]);for(int j=n;j>=i;j--)a[i][j]/=a[i][i];for(int j=1;j<n;j++){if(i==j) continue;double rate=a[j][i]/a[i][i];for(int k=i;k<=n;k++)a[j][k]-=rate*a[i][k];}}for(int i=1;i<=m;i++){if(x[i]!=n)q[i]+=a[x[i]][n]*(1.0/in[x[i]]);if(y[i]!=n)q[i]+=a[y[i]][n]*(1.0/in[y[i]]);}sort(q+1,q+1+m);for(int i=1;i<=m;i++)ans+=q[i]*((m-i+1)*1.0);printf("%.3lf",ans);
}