歡迎訪問~原文出處——博客園-zhouzhendong
去博客園看該題解
題目傳送門 - 洛谷2973
題意概括
有N個城市,M條雙向道路組成的地圖,城市標號為1到N。“西瓜炸彈”放在1號城市,保證城市1至少連接着一個其他城市。“西瓜炸彈”有P/Q的概率會爆炸,每次進入其它城市時,爆炸的概率相同。如果它沒有爆炸,它會隨機的選擇一條道路到另一個城市去,對於當前城市所連接的每一條道路都有相同的可能性被選中。對於給定的地圖,求每個城市“西瓜炸彈”爆炸的概率。
題解
通過概率關系構建方程:
其中in[j]表示節點j的出度,$F_i$ 表示最終在節點 $i$ 爆炸的概率。
$$F_i = \sum_{存在j到 i 的邊}\cfrac{(1-\frac PQ)F_j}{in[j]}+\cfrac PQ \cdot [i=1]$$
然后高斯消元跑一跑就可以了。
代碼
#include <cstring> #include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> using namespace std; const int N=300+5; const double Eps=1e-9; int n,m,P,Q,cnt[N]; bool g[N][N]; double p,a[N][N],x[N]; void Gauss(){ int row=n,col=n,k,c; for (k=c=1;k<=row,c<=col;k++,c++){ int Mk=k; for (int i=k+1;i<=row;i++) if (fabs(a[Mk][c])<fabs(a[i][c])) Mk=i; if (fabs(a[Mk][c])<Eps){ k--; continue; } if (k!=Mk) for (int i=c;i<=col+1;i++) swap(a[k][i],a[Mk][i]); for (int i=k+1;i<=row;i++) for (int j=col+1;j>=c;j--) a[i][j]=a[i][j]-a[k][j]*a[i][c]/a[k][c]; } memset(x,0,sizeof x); for (int i=k;i>=1;i--){ x[i]=a[i][n+1]; for (int j=i+1;j<=n;j++) x[i]-=a[i][j]*x[j]; x[i]/=a[i][i]; } } int main(){ scanf("%d%d%d%d",&n,&m,&P,&Q); p=double(P)/double(Q); memset(g,0,sizeof g); memset(cnt,0,sizeof cnt); for (int i=1,a,b;i<=m;i++){ scanf("%d%d",&a,&b); g[a][b]=g[b][a]=1; cnt[a]++,cnt[b]++; } memset(a,0,sizeof a); a[1][n+1]=p; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++){ if (i==j){ a[i][j]=1; continue; } if (!g[i][j]) continue; double del=(1.0-p)/double(cnt[j]); a[i][j]-=del; } Gauss(); for (int i=1;i<=n;i++) if (fabs(x[i])<Eps) x[i]=0; for (int i=1;i<=n;i++) printf("%.9lf\n",x[i]); return 0; }
以前打錯的公式就讓他暫時存一下吧……