Luogu3232 HNOI2013 游走 高斯消元、期望、贪心

传送门


这种无向图上从一个点乱走到另一个点的期望题目好几道与高斯消元有关

首先一个显然的贪心:期望经过次数越多,分配到的权值就要越小。

设$du_i$表示$i$的度,$f_i$表示点$i$的期望经过次数(我们认为经过表示需要从这个点走出去,所以$f_N=0$),考虑到一条边$(u,v)$经过次数的期望为$\frac{f_u}{du_u}+\frac{f_v}{du_v}$,我们只需要求出$f$数组就可以求出每一条边对应的期望经过次数了。

对于$f$数组,类似于$DP$,我们可以列出一系列式子:$f_u=\frac{1}{du_u}\sum\limits_{(u,v) \in e} f_v+[u==1]$(因为$1$号点是起点,所以需要$+1$),而$f_N=0$,也就是有$N$个未知数、$N$个方程,那么我们可以通过高斯消元得到每一个$f_u$,然后这道题就做完了qaq

 1 #include<bits/stdc++.h>
 2 #define ld long double
 3 #define eps 1e-10
 4 //This code is written by Itst
 5 using namespace std;
 6 
 7 inline int read(){
 8     int a = 0;
 9     bool f = 0;
10     char c = getchar();
11     while(c != EOF && !isdigit(c)){
12         if(c == '-')
13             f = 1;
14         c = getchar();
15     }
16     while(c != EOF && isdigit(c)){
17         a = (a << 3) + (a << 1) + (c ^ '0');
18         c = getchar();
19     }
20     return f ? -a : a;
21 }
22 
23 const int MAXN = 510;
24 ld gauss[MAXN][MAXN] , now[MAXN * MAXN] , ans;
25 struct Edge{
26     int end , upEd;
27 }Ed[MAXN * MAXN * 2];
28 int N , M , cntEd , du[MAXN] , head[MAXN];
29 
30 inline void addEd(int a , int b){
31     Ed[++cntEd].end = b;
32     Ed[cntEd].upEd = head[a];
33     head[a] = cntEd;
34 }
35 
36 inline bool equal(ld a , ld b){
37     return a - eps < b && a + eps > b;
38 }
39 
40 bool cmp(ld a , ld b){
41     return a > b;
42 }
43 
44 int main(){
45 #ifndef ONLINE_JUDGE
46     freopen("3232.in" , "r" , stdin);
47     //freopen("3232.out" , "w" , stdout);
48 #endif
49     N = read();
50     M = read();
51     for(int i = 1 ; i <= M ; ++i){
52         int a = read() , b = read();
53         addEd(a , b);
54         addEd(b , a);
55         ++du[a];
56         ++du[b];
57     }
58     for(int i = 1 ; i < N ; ++i){
59         gauss[i][i] = 1;
60         for(int j = head[i] ; j ; j = Ed[j].upEd)
61             if(Ed[j].end != N)
62                 gauss[i][Ed[j].end] = -1.0 / du[Ed[j].end];
63     }
64     gauss[1][N + 1] = 1;
65     for(int i = 1 ; i < N ; ++i){
66         int j = i;
67         while(j <= N && equal(gauss[j][i] , 0))
68             ++j;
69         if(j != i)
70             for(int k = i ; k <= N + 1 ; ++k)
71                 swap(gauss[i][i] , gauss[j][i]);
72         while(++j <= N)
73             if(!equal(0 , gauss[j][i]))
74                 for(int k = N + 1 ; k >= i ; --k)
75                     gauss[j][k] -= gauss[i][k] / gauss[i][i] * gauss[j][i];
76     }
77     for(int i = N - 1 ; i ; --i){
78         gauss[i][N + 1] /= gauss[i][i];
79         gauss[i][i] = 1;
80         for(int j = i - 1 ; j ; --j)
81             if(!equal(0 , gauss[j][i])){
82                 gauss[j][N + 1] -= gauss[j][i] * gauss[i][N + 1];
83                 gauss[j][i] = 0;
84             }
85     }
86     for(int i = 1 ; i <= cntEd ; i += 2){
87         now[(i + 1) >> 1] = gauss[Ed[i].end][N + 1] / du[Ed[i].end] + gauss[Ed[i + 1].end][N + 1] / du[Ed[i + 1].end];
88     }
89     sort(now + 1 , now + M + 1 , cmp);
90     for(int i = 1 ; i <= M ; ++i)
91         ans += i * now[i];
92     printf("%.3Lf" , ans);
93     return 0;
94 }

猜你喜欢

转载自www.cnblogs.com/Itst/p/10090603.html