LINK
定义 f [ i ] f[i] f[i]表示在点 i i i爆炸的概率
然后似乎不太好转移…
定义 f [ i ] f[i] f[i]表示经过点 i i i的期望次数, P P P表示每小时爆炸的概率, i i i有 i n [ i ] in[i] in[i]条出边
那么这个很好转移,可以使用高斯消元
f [ i ] = ∑ ( i , j ) f [ j ] ∗ ( 1 − P ) ∗ 1 i n [ j ] f[i]=\sum\limits_{(i,j)}f[j]*(1-P)*\frac{1}{in[j]} f[i]=(i,j)∑f[j]∗(1−P)∗in[j]1
对于起点,由于一开始就在起点,所以额外加上一就好了
知道了经过次数,最后乘以 P P P就好了
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
const double eps = 1e-9;
double mp[309][309],p,q;
int n,m,in[maxn];
struct edge{
int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){ d[++cnt] = (edge){v,head[u]},head[u] = cnt; }
void guass(int n)
{
for(int i=1;i<=n;i++)
{
int r = i;
for(int j=i+1;j<=n;j++)
if( fabs(mp[j][i])>fabs(mp[r][i]) ) r = j;
if( i!=r ) swap( mp[i],mp[r] );
if( fabs( mp[r][i] )<eps ) continue;
double div = mp[i][i];
for(int j=i;j<=n+1;j++) mp[i][j] /= div;
for(int j=1;j<=n;j++)
{
if( i==j ) continue;
div = mp[j][i];
for(int k=i;k<=n+1;k++) mp[j][k] -= div*mp[i][k];
}
}
}
int main()
{
cin >> n >> m >> p >> q;
p /= q;
for(int i=1;i<=m;i++)
{
int l,r; cin >> l >> r;
add(l,r); add(r,l); in[l]++, in[r]++;
}
for(int i=1;i<=n;i++)
{
mp[i][i] = 1;
for(int j=head[i];j;j=d[j].nxt )
{
int v = d[j].to;
mp[i][v] -= (1.0-p)/in[v];
}
}
mp[1][n+1] = 1;
guass(n);
for(int i=1;i<=n;i++) printf("%.9lf\n",mp[i][n+1]*p );
}