题目描述 Description
一个无向连通图,顶点从
1
1
编号到,边从
1
1
编号到。小Z在该图上进行随机游走,初始时小Z在
1
1
号顶点,每一步小Z以相等的概率随机选择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z到达号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这
M
M
条边进行编号,使得小Z获得的总分的期望值最小。
输入描述 Input Description
输入文件第一行是正整数和
M
M
,分别表示该图的顶点数
和边数,接下来M行每行是整数,表示顶点
u
u
与顶点之间存在一条边。
输出描述 Output Description
仅包含一个实数,表示最小的期望值,保留3位小数。
样例输入 Sample Input
3 3
2 3
1 2
1 3
样例输出 Sample Output
3.333
样例解释
边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3
数据范围及提示 Data Size & Hint
30%的数据
N≤10
N
≤
10
100%的数据
2≤N≤500
2
≤
N
≤
500
且是一个无向简单连通图。
Solution
很容易就能看出这是一道期望题
我们要知道每条边被经过的期望值,然后期望值小的给一个比较大的编号
怎么求每条边被经过的期望值?
每条边是否被经过只由它所连接的两端节点决定
由于每个点到与之相连的任意一条边的期望相等,所以到某条特定的边的期望就是经过这个点的期望值乘上
1/
1
/
该点的总边数
那么一条边被经过的期望就应该是两端点到这条边的期望值之和
那么我们就将求边的期望转化为求点的期望
显然的,可以看出每个点的期望是由与其相连的点的期望决定的
设
f[x]
f
[
x
]
为点
x
x
的期望,为点
x
x
的总边数,点与其相邻,则
f[x]=∑ki=1f[i]num[i]
f
[
x
]
=
∑
i
=
1
k
f
[
i
]
n
u
m
[
i
]
每个点都能够列出这样一个方程
直接用高斯消元法解即可
注意
点
1
1
与点有些特殊
由于”游走”是从点
1
1
开始,则计算点期望时实际期望应该是原期望+1
若有点和
n
n
相连,那么在计算期望时是不需要将其算入的,因为到了点的时候是不会继续”游走”了
注意着两个点,就没有什么问题了
记得将每条边的两端存起来这样最后计算每条边的期望就很简单了
代码如下
#include <bits/stdc++.h>
using namespace std;
#define N 510
#define eps 1e-8
int to[N*N*2],next[N*N*2],head[N],tot;
int F[N*N],T[N*N];
double q[N*N];
int num[N];
double f[N][N];
double im[N*N*2];
int n,m;
int read() {
int ans=0,flag=1;
char ch=getchar();
while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
void addedge(int u,int v) {
num[u]++;
to[++tot]=v;
next[tot]=head[u];
head[u]=tot;
}
int main() {
n=read(),m=read();
for(int i=1;i<=m;i++) {
int u=read(),v=read();
addedge(u,v);
addedge(v,u);
F[i]=u;T[i]=v;
}
f[1][n]=1;
for(int i=1;i<n;i++) {
f[i][i]=1;
for(int j=head[i];j;j=next[j])
if(to[j]!=n)
f[i][to[j]]=-1.0/num[to[j]];
}
for(int i=1;i<n;i++) {
int now=i;
double s=f[i][i];
for(int j=i+1;j<n;j++)
if(fabs(s-1.0)-fabs(f[j][i]-1.0)>=eps)
{now=j;s=f[j][i];}
if(now!=i) {
for(int j=1;j<=n;j++)
swap(f[i][j],f[now][j]);
}
for(int j=n;j>=i;j--) f[i][j]/=f[i][i];
for(int j=1;j<n;j++)
if(i!=j)
for(int k=n;k>=i;k--)
f[j][k]-=f[j][i]*f[i][k];
}
for(int i=1;i<=m;i++) {
if(F[i]!=n)
q[i]+=f[F[i]][n]*(1.0/num[F[i]]);
if(T[i]!=n)
q[i]+=f[T[i]][n]*(1.0/num[T[i]]);
}
sort(q+1,q+m+1);
double ans=0;
for(int i=1;i<=m;i++)
ans+=q[i]*((m-i+1)*1.0);
printf("%.3lf\n",ans);
return 0;
}