P3232 [HNOI2013]遊走
阿新 • • 發佈:2021-10-11
P3232 [HNOI2013]遊走
期望+概率+高斯消元
推薦閱讀
P3232 遊走 題目傳送門
題目簡述:
給出無向圖包括(\(500\))點,(\(1.25e5\))邊,從\(1\)點出發,到\(n\)點結束,對於每條邊進行任意編號,求出它所有邊的期望和\(\sum_{i=1}^{m}p_i \times num_i\)。
解題:
邊概率-->點概率
可以想到期望和概率,我們可以發現除了\(1\)點比較特殊,\(n\)點非常特殊,其他的點性質就相同了,我們先嚐試把所有點同時考慮,發現對於\(n\)點根本無法考慮,因為到\(n\)點就停了,概率沒法傳給任何點。
我們嘗試把\(1 \thicksim n-1\)
我們可以想到高斯消元:P3389 【模板】高斯消元法。
高斯消元:
然後就可以比較方便的對於每一個點的期望訪問次數列出方程:
對於點\(i\):\(a_{i_1} \times p_1+a_{i_2} \times p_2+...+-p_i+...+a_{i_{n-1}} \times p_{n-1}+a_{i_n} \times p_n=0\)
對於點\(1\):\(-p_1+a_2 \times p_2+...+a_{n-1} \times p_{n-1}+a_n \times p_n=-1\)
為什麼對於點\(1\),為什麼是\(-1\),因為\(p_1\)
所以這個方程便可以順利的解了。
code:
#include<bits/stdc++.h> #define ll long long #define fd(i, a, b) for (ll i = a; i >= b; i--) #define r(i, a) for (ll i = fir[a]; i; i = e[i].nex) #define file(a) freopen(#a ".in", "r", stdin); #define il inline #define db double #define gc getchar() #define f(i,a,b) for(ll i=a;i<=b;i++) using namespace std; const ll maxn=5e2+10,INF=1e16,maxm=2e5; il ll read(){ ll x=0,f=1;char ch=gc; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc;} while(ch>='0'&&ch<='9') x=(x*10)+(ch^48),ch=gc; return x*f; } ll cnt; struct edge{ll to,from;}e[maxm<<1]; il void add(ll a,ll b){e[++cnt].to=b,e[cnt].from=a;} ll n,m; db g[maxn][maxn],out[maxn],one=1.0000000000; il void guess(){ n--; f(i,1,n){ ll M=i; f(j,i+1,n) if(fabs(g[j][i])>fabs(g[M][i])) M=j; swap(g[M],g[i]); f(j,1,n){ if(j==i) continue; db tmp=g[j][i]/g[i][i]; f(k,i+1,n+1) g[j][k]-=tmp*g[i][k]; } } n++; } db p[maxm]; int main() { n=read() ;m=read(); f(i,1,m){ ll a=read(),b=read(); add(a,b); out[a]++,out[b]++; } g[1][n]=-1; f(i,1,n-1) g[i][i]=-1; f(i,1,m){ ll a=e[i].to,b=e[i].from; if(a==n||b==n) continue; g[a][b]=(one/out[b]); g[b][a]=(one/out[a]); } guess(); f(i,1,n-1) g[i][n]/=g[i][i]; f(i,1,m){ ll a=e[i].to,b=e[i].from; p[i]=g[a][n]/out[a]+g[b][n]/out[b]; } // f(i,1,m) cout<<p[i]<<endl; sort(p+1,p+1+m); db ans=0; f(i,1,m) ans+=(m-i+1)*p[i]; printf("%.3lf",ans); }