山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 3143 [Hnoi2013]游走(贪心,高斯消元,期望方程)

 

【题目链接】

 

    http://www.lydsy.com/JudgeOnline/problem.php?id=3143

 

【题意】

 

    给定一个无向图,从1走到n,走过一条边得到的分数为边的标号,问一个边的标号方法,使得路径上得分最少。

 

【思路】

 

    设f[i]表示经过i点的期望次数。有:

        f[1]=1+sigma{ f[v] }

        f[u]=sigma{ f[v] }

    特别地,令f[n]=0,因为n点不会对任何连边做出贡献,于是记之为0。

    于是得到了n个线性方程组,可以用高斯消元法求解。

    对于一条边(u,v)的期望经过次数为:

        e=f[u]/du[u] + f[v]/du[v]

    du[u]为u点的度数。

    然后对每条边贪心地赋值,期望经过次数越大地赋值越小。

 

【代码】

 

 1 #include<set>
 2 #include<cmath>
 3 #include<queue>
 4 #include<vector>
 5 #include<cstdio>
 6 #include<cstring>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
11 using namespace std;
12 
13 typedef long long ll;
14 const int N = 505; 
15 const int M = N*N;
16 
17 ll read() {
18     char c=getchar();
19     ll f=1,x=0;
20     while(!isdigit(c)) {
21         if(c=='-') f=-1; c=getchar();
22     }
23     while(isdigit(c))
24         x=x*10+c-'0',c=getchar();
25     return x*f;
26 }
27 
28 struct Edge {
29     int v,nxt;
30 }e[M];
31 int en=1,front[N];
32 void adde(int u,int v) 
33 {
34     e[++en]=(Edge){v,front[u]}; front[u]=en;
35 }
36 
37 int n,m,du[N],flag[N][N];
38 double ef[N],a[N][N]; int tot;
39 
40 void gause()
41 {
42     for(int i=1;i<=n;i++)
43     {
44         int r=i;
45         for(int j=i+1;j<=n;j++)
46             if(fabs(a[j][i])>fabs(a[r][i])) r=i;
47         if(r!=i) for(int j=1;j<=n+1;j++) swap(a[i][j],a[r][j]);
48         for(int j=n+1;j>=i;j--)
49             for(int k=i+1;k<=n;k++)
50                 a[k][j]-=a[k][i]/a[i][i]*a[i][j];
51     }
52     for(int i=n;i;i--)
53     {
54         for(int j=i+1;j<=n;j++)
55             a[i][n+1]-=a[i][j]*a[j][n+1];
56         a[i][n+1]/=a[i][i];
57     }
58 }
59 
60 int main()
61 {
62     n=read(),m=read();
63     int u,v;
64     FOR(i,1,m) 
65     {
66         u=read(),v=read();
67         adde(u,v),adde(v,u);
68         du[u]++,du[v]++;
69     }
70     FOR(u,1,n-1) 
71     {
72         if(u==1) a[u][n]=1;
73         a[u][u]=1;
74         trav(u,i) 
75         {
76             int v=e[i].v;
77             if(v!=n) a[u][v]-=1.0/du[v];
78         }
79     }
80     a[1][n]=1;
81     n--;
82     gause();
83     FOR(u,1,n) 
84     {
85         trav(u,i) 
86         {
87             int v=e[i].v;
88             if(v!=u&&!flag[u][v]) 
89                 ef[++tot]=a[u][n+1]/du[u]+a[v][n+1]/du[v],
90                 flag[u][v]=flag[v][u]=1;
91         }
92     }
93     sort(ef+1,ef+tot+1);
94     double ans=0.0;
95     FOR(i,1,tot)
96         ans+=ef[i]*(tot-i+1);
97     printf("%.3lf\n",ans);
98     return 0;
99 }

 

posted on 2016-03-31 16:43  hahalidaxin  阅读(310)  评论(0编辑  收藏  举报