数组开小引发的惨案…
这题算边的期望转化为算点的期望.
令p[i][j]表示i点到j点的概率
e[i]表示到第i个点的期望
d[i]表示到第i条边的期望
有
d[i]=e[u[i]]∗1out[u[i]]+e[v[i]]∗1out[v[i]]
d
[
i
]
=
e
[
u
[
i
]
]
∗
1
o
u
t
[
u
[
i
]
]
+
e
[
v
[
i
]
]
∗
1
o
u
t
[
v
[
i
]
]
有
∑ni=1(p[i][j]∗e[i])=e[j]
∑
i
=
1
n
(
p
[
i
]
[
j
]
∗
e
[
i
]
)
=
e
[
j
]
其中当
j=1
j
=
1
时,有
1+∑ni=1(p[i][1]∗e[i])=e[1]
1
+
∑
i
=
1
n
(
p
[
i
]
[
1
]
∗
e
[
i
]
)
=
e
[
1
]
要注意到n的时候就会停下来,所以
∑ni=1[p[n][i]==0]=0
∑
i
=
1
n
[
p
[
n
]
[
i
]
==
0
]
=
0
然后高斯消元即可
c++代码如下:
#include<bits/stdc++.h>
#define eps 1e-9
#define rep(i,x,y) for(register int i = x ; i <= y;++ i)
#define repd(i,x,y) for(register int i = x ;i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
x = 0;char c;int sign = 1;
do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
const int N = 505;
long double a[N][N],e[N],f[N*N],ans;
int n,m,size[N];
struct Edge { int u,v; }edge[N*N];
int main()
{
read(n); read(m);
rep(i,1,m)
{
read(edge[i].u); read(edge[i].v);
++ size[edge[i].u]; ++ size[edge[i].v];
}
a[1][n + 1] = -1;
rep(i,1,n) a[i][i] = -1;
rep(i,1,m)
{
if(edge[i].u != n) a[edge[i].u][edge[i].v] += 1.0/size[edge[i].v];
if(edge[i].v != n) a[edge[i].v][edge[i].u] += 1.0/size[edge[i].u];
}
rep(i,1,n)
{
rep(j,i + 1,n)
if(abs(a[i][i]) < abs(a[j][i]))
swap(a[i],a[j]);
if(abs(a[i][i]) < eps) continue;
rep(j,i + 1,n)
{
double c = a[j][i]/a[i][i];
rep(k,i,n + 1)
a[j][k] -= a[i][k] * c;
}
}
repd(i,n,1)
{
rep(j,i + 1,n)
a[i][n + 1] -= a[i][j]*e[j];
if(abs(a[i][i]) > eps) e[i] = a[i][n + 1] / a[i][i];
}
rep(i,1,m)
{
if(edge[i].u != n && size[edge[i].u]) f[i] += e[edge[i].u]/size[edge[i].u];
if(edge[i].v != n && size[edge[i].v]) f[i] += e[edge[i].v]/size[edge[i].v];
}
sort(f + 1,f + 1 + m);
rep(i,1,m) ans += f[m-i+1] * i;
cout << fixed << setprecision(3) << ans << endl;
return 0;
}