题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3143
显然如果一条边期望被走过的次数越多,我们就应该给它的编号越小。
所以问题变为如何求每一条边被经过的期望次数。
考虑直接求边的期望有点困难。
设:${g[i]}$表示经过第$i$条边的期望次数,${f[i]}$表示经过第$i$个点的期望次数,${du[i]}$表示第$i$个点的度数。
对于一条边$i$,假设这条边的两段的点分别为${x,y}$,则${g[i]=frac{f[x]}{du[x]}*frac{f[y]}{du[y]}}$
所以问题变为如何求每一个点被经过的期望次数
设$e[x][y]$表示点$x,y$之间有连边。这就很裸了,${f[i]=sum (frac{f[x]}{du[x]}left [ e[i][x]=1 ight ] )}$,其中$n$号点只能走进去而不能出来,所以忽略不管,$1$号点应当强制$+1$(因为一开始就从$1$号点开始)
这样就得到了一个$n-1$个未知数和$n-1$个式子的方程组,高斯消元求得每个未知数的解(即${f[i]}$),然后求出${g[i]}$,然后从大到小排序。
$${sum _{i=1}^{m}g[i]*i}$$
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 510 10 #define llg long long 11 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 12 llg n,m; 13 double a[maxn][maxn],du[maxn],f[maxn],g[maxn*maxn]; 14 15 struct Edge{llg x,y;}e[maxn*maxn]; 16 17 bool cmp(double x,double y){return x>y;} 18 19 void guass() 20 { 21 llg r; 22 for (llg i=1;i<=n;i++) 23 { 24 r=i; 25 for (llg j=i+1;j<=n;j++) if (fabs(a[j][i])>fabs(a[r][i])) r=j; 26 if (r!=i) for (llg j=1;j<=n+1;j++) swap(a[r][j],a[i][j]); 27 28 for (llg k=i+1;k<=n;k++) 29 { 30 double F=a[k][i]/a[i][i]; 31 for (llg j=i;j<=n+1;j++) a[k][j]-=F*a[i][j]; 32 } 33 } 34 35 for (llg i=n;i>=1;i--) 36 { 37 for (llg j=i+1;j<=n;j++) a[i][n+1]-=f[j]*a[i][j]; 38 f[i]=a[i][n+1]/a[i][i]; 39 } 40 } 41 42 void init() 43 { 44 llg x,y; 45 cin>>n>>m; 46 for (llg i=1;i<=m;i++) 47 { 48 scanf("%lld%lld",&e[i].x,&e[i].y); 49 du[e[i].x]++,du[e[i].y]++; 50 } 51 for (llg i=1;i<=m;i++) 52 { 53 x=e[i].x,y=e[i].y; 54 if (y!=n) {a[x][y]=1.00/du[y];} 55 if (x!=n) {a[y][x]=1.00/du[x];} 56 } 57 for (llg i=1;i<n;i++) a[i][i]=-1; 58 a[1][n]=-1; 59 n--; 60 } 61 62 int main() 63 { 64 yyj("walk"); 65 init(); 66 guass(); 67 for (llg i=1;i<=m;i++) g[i]=f[e[i].x]/du[e[i].x]+f[e[i].y]/du[e[i].y]; 68 double ans=0; 69 sort(g+1,g+m+1,cmp); 70 for (llg i=1;i<=m;i++) ans+=(double)i*g[i]; 71 printf("%.3lf",ans); 72 return 0; 73 }