深夜肝题。。。有害身心健康QAQ
设f[i]为到达i的概率,d[i]为i的度数。
因为无限久之后炸弹爆炸的概率是1,所以最后在i点爆炸的概率实际上就是f[i]/sigma(f[])
列出方程组 f[i]=sigma(f[to]*(1-p/q)/d[to]+[i==1]*(1-p/q))
然后就可以高斯消元了
高斯消元的方法:自己的那一位是1,to的每一位上为-(1-p/q)/d[to],n+1位上为0,这样就相当于x减去所有to为0。1的n+1上为1-p/q,因为炸弹还可能在自己这里不跑。
这题实际上还有另一个思路,利用期望来计算,这里就直接贴博客了。。。
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=310,inf=1e9; const double eps=1e-13; struct poi{int too,pre;}e[maxn*maxn*2]; int n,m,p,q,to,x,y,tot,d[maxn],last[maxn]; double sum,a[maxn][maxn]; void read(int &k) { int f=1;k=0;char c=getchar(); while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar(); k*=f; } void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;} void gauss() { for(int i=1;i<=n;i++) { for(to=i;to<=n;to++)if(fabs(a[to][i])>eps)break; if(to!=i)for(int j=1;j<=n+1;j++)swap(a[i][j],a[to][j]); double x=a[i][i];for(int j=1;j<=n+1;j++)a[i][j]/=x; for(int j=1;j<=n;j++) if(i!=j) { x=a[j][i]; for(int k=1;k<=n+1;k++) a[j][k]-=x*a[i][k]; } } } int main() { read(n);read(m);read(p);read(q);double pro=1.0*p/q; for(int i=1;i<=m;i++) { read(x);read(y); d[x]++;d[y]++; add(x,y);add(y,x); } for(int i=1;i<=n;i++) { a[i][i]=1; for(int j=last[i];j;j=e[j].pre) a[i][e[j].too]-=(1-pro)/d[e[j].too]; } a[1][n+1]=1-pro; gauss(); for(int i=1;i<=n;i++)sum+=a[i][n+1]; for(int i=1;i<=n;i++)printf("%.9lf ",a[i][n+1]/sum); return 0; }