​LINK​

定义 f [ a ] [ b ] f[a][b] f[a][b]为状态 ( a , b ) (a,b) (a,b)出现的期望次数

( a , b ) (a,b) (a,b)表示两个男孩所在的房间

f [ a ] [ b ] = f [ a 1 ] [ b 1 ] ∗ p 1 + f [ a 2 ] [ b 2 ] ∗ p 2 . . . f [ a x ] [ b x ] ∗ p x f[a][b]=f[a_1][b_1]*p_1+f[a_2][b_2]*p_2...f[a_x][b_x]*p_x f[a][b]=f[a1][b1]∗p1+f[a2][b2]∗p2...f[ax][bx]∗px

其中 ( a i , b i ) (a_i,b_i) (ai,bi)状态有 p i p_i pi的概率转移到 ( a , b ) (a,b) (a,b)状态

当然如果是初始位置,需要多加一,因为一开始就在这个状态

f [ a ] [ b ] = f [ a 1 ] [ b 1 ] ∗ p 1 + f [ a 2 ] [ b 2 ] ∗ p 2 . . . f [ a x ] [ b x ] ∗ p x + 1 f[a][b]=f[a_1][b_1]*p_1+f[a_2][b_2]*p_2...f[a_x][b_x]*p_x+1 f[a][b]=f[a1][b1]∗p1+f[a2][b2]∗p2...f[ax][bx]∗px+1

那么总的状态数不会超过 n 2 n^2 n2,高斯消元即可,复杂度 O ( n 6 ) O(n^6) O(n6)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 509;
const double eps = 1e-8;
int a,b,n,m;
double mp[maxn][maxn],p[maxn];
vector<int>vec[maxn];
int id(int a,int b){ return n*(a-1)+b; }
void guess(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[i][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 >> a >> b;
for(int i=1;i<=m;i++)
{
int l,r; cin >> l >> r;
vec[l].push_back( r );
vec[r].push_back( l );
}
for(int i=1;i<=n;i++) {cin >> p[i]; vec[i].push_back( i ); }
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)//枚举每一个状态
{
int now = id(i,j);
mp[now][now] = 1;
if( i==j ) continue;
for( auto u:vec[i] )
for( auto v:vec[j] )
{
int nxt = id(u,v);
double P = 1;
if( u==i ) P *= p[i];
else P *= ( 1-p[i] )/( vec[i].size()-1 ) ;
if( v==j ) P *= p[j];
else P *= ( 1-p[j] )/( vec[j].size()-1 );
mp[nxt][now] -= P;
}
}
mp[id(a,b)][n*n+1] = 1;
guess( n*n );
for(int i=1;i<=n;i++) printf("%.6lf ",mp[id(i,i)][n*n+1] );
}