BZOJ 3143 游走(高斯消元)

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

思路:显然,需要求出每条边的期望经过次数,然后排序贪心赋值即可,但是每条边的期望经过次数是什么呢?

是 E(e)=E(u)/D(u) + E(v)/D(v) (u,v∈e)

所以做法就是先求出每个点的期望经过次数,还有,就是对于第n个点,它的期望在最后统计的时候要看做0,因为到了n点就不会再出来了。

 

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 struct edge{
 7     int u,v;
 8     double w;
 9 }e[500005];
10 int n,m,du[500005],go[1005][1005];
11 double a[1010][1010],p[500005];
12 bool Cmp(edge q,edge w){
13     return q.w>w.w;
14 }
15 void gauss(){
16     int to,now=1;
17     for (int i=1;i<=n;i++){
18         for (to=now;to<=n;to++) if (a[to][i]!=0) break;
19         if (to>n) continue;
20         if (to!=now) for (int j=1;j<=n+1;j++) std::swap(a[now][j],a[to][j]);
21         double t=a[now][i];
22         for (int j=1;j<=n+1;j++) a[now][j]/=t;
23         for (int j=1;j<=n;j++)
24          if (j!=now){
25                 t=a[j][i];
26                 for (int k=1;k<=n+1;k++)
27                  a[j][k]-=t*a[now][k];
28         }
29         now++;
30     }
31 }
32 int main(){
33     scanf("%d%d",&n,&m);
34     int tot=0;
35     for (int i=1;i<=m;i++){
36         int x,y;
37         scanf("%d%d",&x,&y);
38         if (x==y) continue;
39         e[++tot].u=x;e[tot].v=y;
40         go[x][++go[x][0]]=y;
41         go[y][++go[y][0]]=x;
42         du[e[tot].u]++;
43         du[e[tot].v]++;
44     }
45     m=tot;
46     for (int i=1;i<n;i++) a[i][i]=1;
47     for (int i=1;i<n;i++){
48         for (int j=1;j<=go[i][0];j++){
49             int t=go[i][j];
50             if (t==n) continue;
51             a[i][t]-=1.0/du[t];
52         }
53     }
54     n--;
55     a[1][n+1]=1;
56     gauss();
57     for (int i=1;i<=n;i++) p[i]=a[i][n+1];
58     for (int i=1;i<=m;i++)
59      e[i].w=((double)p[e[i].u])/((double)du[e[i].u])+((double)p[e[i].v])/((double)du[e[i].v]);
60     std::sort(e+1,e+1+m,Cmp);
61     double ans=0;
62     for (int i=1;i<=m;i++) ans+=e[i].w*i;
63     printf("%.3f\n",ans);
64 }

 

posted @ 2016-05-27 18:52  GFY  阅读(234)  评论(0编辑  收藏  举报