码迷,mamicode.com
首页 > 其他好文 > 详细

【HNOI2013】游走

时间:2017-04-07 19:46:34      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:iostream   space   margin   data   for   编号   name   简单   while   

P2351 - 【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。
由于搬运者发现官方数据没有程序能跑对最后两个点,遂修改其结果。

 

 

先算出到每个点的期望值f[i]=Σf[to]/deg[to],然后因为1是起点所以f[1]还要加1。
然后可以发现这个式子的意思就是
f[i]加上每个可以走到i这个点的期望*走到i的概率,
因为走到n就不能走了,所以为了消除n对别的点的影响,
f[n]=0
其实我推方程半天没推出来就是因为这个f[n]=0,还有f[1]要加1
然后就可以高斯消元法解方程,这样就可以把点的期望求出来了。
然后边的期望就是p[i]=p[u]/deg[u]+p[v]/deg[v](u,v是这条边连的两个点)
然后贪心算答案就可以了。
 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 #define maxn 510
15 using namespace std;
16 struct data{
17   int nex,to;
18 }e[maxn*maxn*2];
19 double deg[maxn],a[maxn][maxn],p[maxn*maxn];
20 int head[maxn],edge=0,n;
21 void add(int from,int to){
22   e[++edge].nex=head[from];
23   e[edge].to=to;
24   head[from]=edge;
25 }
26 void gauss(){
27   for(int i=1;i<=n;i++){
28     int t=i;
29     while(!a[t][i] && t<=n) t++;
30     if(t>n) continue;
31     for(int j=1;j<=n+1;j++) swap(a[t][j],a[i][j]);
32     double k=a[i][i];
33     for(int j=i;j<=n+1;j++) a[i][j]/=k;
34     for(int j=1;j<=n;j++)
35       if(j!=i && a[j][i]){
36     k=a[j][i];
37     for(int p=i;p<=n+1;p++)
38       a[j][p]-=k*a[i][p];
39       }
40   }
41 }
42 bool cmp(const double &a,const double &b){
43   return a>b;
44 }
45 int main()
46 {
47   freopen("walk.in","r",stdin);
48   freopen("walk.out","w",stdout);
49   int m,x,y;
50   scanf("%d%d",&n,&m);
51   for(int i=1;i<=m;i++){
52     scanf("%d%d",&x,&y);
53     add(x,y),add(y,x),deg[x]++,deg[y]++;
54   }
55   for(int i=1;i<n;i++){
56     if(i==1) a[i][n+1]=1;
57     a[i][i]=1;
58     for(int j=head[i];j;j=e[j].nex)
59       a[i][e[j].to]-=1/deg[e[j].to];
60   }
61   a[n][n]=0;
62   gauss();
63   for(int i=1;i<=edge;i+=2)
64     p[(i+1)/2]=(a[e[i].to][n+1]/deg[e[i].to])+(a[e[i+1].to][n+1]/deg[e[i+1].to]);
65   sort(p+1,p+m+1,cmp);
66   double ans=0.0;
67   for(int i=1;i<=m;i++)
68     ans+=p[i]*i;
69   printf("%.3lf",ans);
70   return 0;
71 }

 



【HNOI2013】游走

标签:iostream   space   margin   data   for   编号   name   简单   while   

原文地址:http://www.cnblogs.com/pantakill/p/6679637.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!