题意
给你一张 n n n个点 m m m条边的无向图,最开始有一颗炸弹在一号节点,它有 p q \frac{p}{q} qp的概率爆炸,如果没有爆炸,它会等概率的移动到另一个与当前节点相连的点,问炸弹分别在每个点爆炸的概率。
思路
考虑一维的向量矩阵 A A A,第 i i i位表示炸弹停在 i i i点的概率是 A i A_{i} Ai,那么初始时炸弹停在 1 1 1号节点 A = ( 1 , 0 , 0 , . . . , 0 , 0 ) A=(1,0,0,...,0,0) A=(1,0,0,...,0,0),考虑如何转移,设 D i D_{i} Di表示 i i i点的度数,那么有 A i A_{i} Ai= ∑ ( 1 − p q ) ∗ 1 D j ∗ A j \sum(1-\frac{p}{q})*\frac{1}{D_{j}}*A_{j} ∑(1−qp)∗Dj1∗Aj( j j j为 i i i能到达的点)。那么可以建立一个 n ∗ n n*n n∗n的矩阵 B B B, B i , j = ( 1 − p q ) ∗ 1 D j B_{i,j}=(1-\frac{p}{q})*\frac{1}{D_{j}} Bi,j=(1−qp)∗Dj1,那么最终答案矩阵 a n s ans ans= ( A + A ⋅ B + A ⋅ B ⋅ B + . . . + A ⋅ B o o ) (A+A\cdot B+A\cdot B\cdot B+...+A\cdot B^{oo}) (A+A⋅B+A⋅B⋅B+...+A⋅Boo),等比数列求和得到 a n s = A I − B ans=\frac{A}{I-B} ans=I−BA, a n s ⋅ ( I − B ) = A ans\cdot (I-B)=A ans⋅(I−B)=A,直接高斯消元即可。
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const double eps=1e-15;
const int N=500;
struct node{int y,n;}e[100010];
int lin[100010],d[N],len=0,n,m,x,y;
double a[N][N],ans[N],p,q;
void read(int x,int y)
{e[++len].y=y,e[len].n=lin[x],lin[x]=len;}
bool gauss(){
rep(i,1,n){
int k=i;
rep(j,i+1,n)if(fabs(a[j][i])>fabs(a[k][i]))k=j;
if(fabs(a[k][i])<=eps)return 0;
if(k!=i)swap(a[k],a[i]);
double tmp=a[i][i];
rep(j,i,n+1)a[i][j]/=tmp;
rep(j,i+1,n){
tmp=a[j][i];
rep(k,i,n+1)a[j][k]-=a[i][k]*tmp;
}
}
ans[n]=a[n][n+1];
per(i,n-1,1){
ans[i]=a[i][n+1];
rep(j,i+1,n){
ans[i]-=a[i][j]*ans[j];
}
}return 1;
}
int main(){
scanf("%d%d%lf%lf",&n,&m,&p,&q);p/=q;
rep(i,1,m){
scanf("%d%d",&x,&y);
read(x,y);read(y,x);
d[x]++,d[y]++;
}
a[1][n+1]=1;
rep(x,1,n){
a[x][x]=1;
for(int i=lin[x];i;i=e[i].n){
int y=e[i].y;
a[x][y]=-(1.0-p)/d[y];
}
}
gauss();
rep(i,1,n)printf("%.9lf\n",ans[i]*p+eps);
return 0;
}