1. 程式人生 > >Luogu3232 HNOI2013 遊走 高斯消元、期望、貪心

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 }