BZOJ3143 [HNOI2013]游走

Description

一个无向连通图,顶点从1编号到N,边从1编号到M。 
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。 
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

Input

第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。

Output

仅包含一个实数,表示最小的期望值,保留3位小数。

Sample Input

3 3
2 3
1 2
1 3

Sample Output

3.333

HINT

边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。

权当复习高斯消元喽
如果我们能求出每条边被经过的期望次数,那么只要从大到小标号就好了
而求边是比较难的,相对的求点更简单。。。
而一条边被经过的次数可以由两个端点算出
现在只需要求点即可,我们发现每个点的期望都跟所有跟他相邻的点有关
也就是说我们能列出n个方程,接下来就要用高斯消元来处理
f就是那个矩阵,因为n比较特殊所以就作为存等式右边的一列,n*(n-1)
首先1号点在开始时必须被经过1次,f[1][n]+=1
然后在各项填上系数,使得f[i][n]=0
之后就是消元
在这里是将f[j][i]绝对值最大的那一行换到第i行上
接下来再把f[i][i]调整成1,在所有第i列上不为0的行上消去第i列
这样做结束后直接f[i][n]就是i的答案
最后统计边,标号,输出答案
 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #define N 505
 5 #define eps 1e-8
 6 using namespace std;
 7 int n,m;
 8 int to[N*N*2],nxt[N*N*2],h[N],etop;
 9 int F[N*N],T[N*N];
10 double q[N*N];
11 int num[N];
12 double f[N][N];
13 double im[N*N*2];
14 void add(int u,int v){
15     num[u]++;to[++etop]=v;
16     nxt[etop]=h[u];h[u]=etop;
17 }
18 int main(){
19     scanf("%d%d",&n,&m);
20     for(int i=1,u,v;i<=m;i++){
21         scanf("%d%d",&u,&v);
22         add(u,v);add(v,u);
23         F[i]=u;T[i]=v;
24     }
25     f[1][n]=1;
26     for(int i=1;i<n;i++){
27         f[i][i]=1;
28         for(int j=h[i];j;j=nxt[j])
29             if(to[j]!=n)
30                 f[i][to[j]]=-1.0/num[to[j]];
31     }
32     for(int i=1;i<n;i++){
33         int now=i;
34         double s=f[i][i];
35         for(int j=i+1;j<n;j++)
36             if(fabs(f[j][i])-fabs(s)>eps){now=j;s=f[j][i];}
37         if(now!=i){
38             for(int j=1;j<n;j++)
39                 swap(f[i][j],f[now][j]);
40         }
41         for(int j=n;j>=i;j--)f[i][j]/=f[i][i];
42         for(int j=1;j<n;j++)
43             if(i!=j)
44                 for(int k=n;k>=i;k--)
45                     f[j][k]-=f[j][i]*f[i][k];
46     }
47     for(int i=1;i<=m;i++){
48         if(F[i]!=n)
49             q[i]+=f[F[i]][n]*(1.0/num[F[i]]);
50         if(T[i]!=n)
51             q[i]+=f[T[i]][n]*(1.0/num[T[i]]);
52     }
53     sort(q+1,q+1+m);
54     double ans=0;
55     for(int i=1;i<=m;i++)
56         ans+=q[i]*((m-i+1)*1.0);
57     printf("%.3lf",ans);
58     return 0;
59 }
View Code

 

posted @ 2019-01-10 15:12  瞬闪影  阅读(128)  评论(0编辑  收藏  举报