[HNOI2013]游走

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制
3 3
2 3
1 2
1 3
输出样例#1: 复制
3.333

说明

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

算出每条边的期望走过次数

贪心,期望大的给小编号,答案最小

 

每条边的期望走过次数可以由两个端点的期望次数算出来

E[i]=e[u]/d[u]+e[v]/d[v]

那么问题就转为求点期望走过次数

对于每一个点u

我们有e[u]=∑(e[v]/d[v])

特例:

1是起点,期望步数+1

n是终点,期望为0

于是列出n-1个方程,高斯消元

此代码在洛谷玄学WA,但BZOJ能AC

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 struct link
 8 {
 9   int u,v;
10 }Link[500101];
11 struct Node
12 {
13   int next,to;
14 }edge[500101];
15 int head[601],num,n,m;
16 double a[601][601],ans[601],d[601],E[500101],anss;
17 void add(int u,int v)
18 {
19   num++;
20   edge[num].next=head[u];
21   head[u]=num;
22   edge[num].to=v;
23 }
24 const double eps=1e-12;
25 int dcmp(double x)
26 {
27   if (x<=eps&&x>=-eps) return 0;
28   return (x>0)?1:-1;
29 }
30 void gauss()
31 {int i,now,j,k;
32   for (i=1;i<=n;i++)
33     {
34       now=i;
35       for (j=i+1;j<=n;j++)
36     if (dcmp(a[now][i]-a[j][i])<0)
37       now=j;
38       if (now!=i)
39       for (j=i;j<=n+1;j++)
40     swap(a[now][j],a[i][j]);
41       for (j=i+1;j<=n;j++)
42     if (dcmp(a[j][i]))
43     {
44       double t=a[j][i]/a[i][i];
45       for (k=i+1;k<=n+1;k++)
46         a[j][k]-=a[i][k]*t;
47     }
48     }
49   for (i=n;i>=1;i--)
50     {
51       for (j=i+1;j<=n;j++)
52     {
53       a[i][n+1]-=a[i][j]*ans[j];
54     }
55       ans[i]=a[i][n+1]/a[i][i];
56     }
57 }
58 int main()
59 {int i,u,v,j;
60   cin>>n>>m;
61   for (i=1;i<=m;i++)
62     {
63       scanf("%d%d",&u,&v);
64       add(u,v);add(v,u);
65       Link[i].u=u;Link[i].v=v;
66       d[u]+=1.0;d[v]+=1.0;
67     }
68   a[1][n]=-1.0;
69   for (i=1;i<n;i++)
70     a[i][i]=-1.0;
71   for (i=1;i<n;i++)
72     {
73       for (j=head[i];j;j=edge[j].next)
74     {
75       int v=edge[j].to;
76       if (v!=n)
77         {
78           a[i][v]=1.0/d[v];
79         }
80     }
81     }
82   n--;
83   gauss();
84   for (i=1;i<=m;i++)
85       E[i]=ans[Link[i].u]/d[Link[i].u]+ans[Link[i].v]/d[Link[i].v];
86   sort(E+1,E+m+1);
87   for (i=1;i<=m;i++)
88     anss+=E[i]*(m-i+1.0);
89   printf("%.3lf\n",anss);
90 }

 

posted @ 2017-10-24 21:20  Z-Y-Y-S  阅读(258)  评论(0编辑  收藏  举报