【题意】给定无向图,炸弹开始在1,在每个点爆炸概率p/q,不爆炸则等概率往邻点走,求在每个点爆炸的概率。
【算法】数学概率期望+高斯消元
【题解】令f[i]表示炸弹到达i点的概率(之前不爆炸)。
f[i]=∑f[j]*(1-Q)/d[j]
特别的,f[1]=∑f[j]*(1-Q)/d[j]+1(一开始就到达)。
只要一个点到就是到达,故使用概率加法。
使用高斯消元求解方程组,最后ansi=f[i]*Q。
另一种思路,由于炸弹最终爆炸概率为1,所以sum=∑f[i],ansi=f[i]/sum
此题还有另一种解法,计算每个点到达次数的期望,到达概率和到达次数正相关(注意方程步数+1)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=310,maxm=50010; struct edge{int v,from;}e[maxm*2]; int first[maxn],tot,d[maxn],n,m,p,q; double f[maxn][maxn]; void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;d[v]++;} void gauss(){ for(int i=1;i<=n;i++){ int t=i; for(int j=i+1;j<=n;j++)if(f[j][i]>f[t][i])t=j; if(t!=i)for(int j=i+1;j<=n;j++)swap(f[i][j],f[t][j]); for(int j=i+1;j<=n;j++) for(int k=n+1;k>=i;k--) f[j][k]-=f[j][i]/f[i][i]*f[i][k]; } for(int i=n;i>=1;i--){ for(int j=i+1;j<=n;j++)f[i][n+1]-=f[i][j]*f[j][n+1]; f[i][n+1]/=f[i][i]; } } int main(){ scanf("%d%d%d%d",&n,&m,&p,&q);double Q=1.0*p/q; int u,v; for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); insert(u,v);insert(v,u); } f[1][n+1]=1; for(int k=1;k<=n;k++){ f[k][k]=1; for(int i=first[k];i;i=e[i].from)f[k][e[i].v]=-(1-Q)/d[e[i].v]; } gauss(); for(int i=1;i<=n;i++)printf("%.9lf\n",f[i][n+1]*Q); return 0; }
时间: 2024-10-12 21:01:27