1. 程式人生 > >【BZOJ3143】【HNOI2013】遊走 高斯消元

【BZOJ3143】【HNOI2013】遊走 高斯消元

pri OS 發現 scan span 高斯 hnoi2013 c代碼 main

題目傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=3143

我們令$P_i$表示從第i號點出發的期望次數。則$P_n$顯然為$0$。

對於$P_2~P_{n-1}$,則有$P_i= \sum \frac{P_j} {d_j}$,其中節點j與節點i有邊相連,$d_j$表示節點j的度數。

對於$P_1$,則有$P_i=1+ \sum \frac{P_j} {d_j}$。

不難發現其實就是一個$n$元一次方程組,我們可以通過高斯消元求出每一個$P_i$。

對於一條邊$(x,y)$,經過這條邊的期望次數為$ \frac {P_x} {d_x} + \frac {P_y} {d_y}$,我們設此值為$p_i$ 。

我們把期望經過次數從大到小排序,則答案為$\sum_{i=1}^{n} p_i \times i$。

然後就做完了。

AC代碼如下:

 1 #include<bits/stdc++.h>
 2 #define M 505
 3 using namespace std;
 4 int a[M][M]={0},n,m;
 5 double f[M][M]={0},p[M]={0},du[M]={0};
 6 
 7 void solve(){
 8     for(int i=1;i<=n;i++){
 9         for(int j=i+1;j<=n;j++){
10 double x=f[j][i]/f[i][i]; 11 for(int k=i;k<=n+1;k++) 12 f[j][k]-=x*f[i][k]; 13 } 14 } 15 for(int i=n;i;i--){ 16 for(int j=i+1;j<=n;j++) 17 f[i][n+1]-=f[i][j]*p[j]; 18 p[i]=f[i][n+1]/f[i][i]; 19 } 20 } 21
int X[M*M]={0},Y[M*M]={0}; double hh[M*M]={0}; 22 int main(){ 23 scanf("%d%d",&n,&m); 24 for(int i=1;i<=m;i++){ 25 int x,y; scanf("%d%d",&x,&y); 26 a[x][y]=a[y][x]=1; 27 du[x]++; du[y]++; 28 X[i]=x; Y[i]=y; 29 } 30 f[1][n+1]=-1; f[n][n]=1; 31 for(int i=1;i<n;i++){ 32 f[i][i]=-1; 33 for(int j=1;j<=n;j++) if(a[i][j]) 34 f[i][j]=1/du[j]; 35 } 36 solve(); 37 for(int i=1;i<=m;i++) 38 hh[i]=p[X[i]]/du[X[i]]+p[Y[i]]/du[Y[i]]; 39 sort(hh+1,hh+m+1); 40 double ans=0; 41 for(int i=1;i<=m;i++) 42 ans+=hh[i]*(m-i+1); 43 printf("%.3lf\n",ans); 44 }

【BZOJ3143】【HNOI2013】遊走 高斯消元