题意
有两个人在无向图中走,初始时在
(A,B)
,
p[i]
的概率留在原地,
(1−p[i])
的概率等可能的往出边走,询问两个人在1~n每个房间相遇的概率
n≤20
分析
考虑两个人会构成
n2
种状态
(a,b)
则可以列出方程,设
P(a,b)
为经过
(a,b)
这个状态的概率
设
p[i]
代表留在当前点的概率,
Out[i]
代表走出当前点的概率
Out[i]=(1−p[i])/degree[i]
P(a,b)=p[a]∗p[b]∗P(a,b)+Out[u]∗p[b]∗P(u,b)+p[a]∗Out[v]∗P(a,v)+Out[u]∗Out[v]∗P(u,v)
- 注意到如果两人在同一个房间的话就不可以再走了,所以当u==v的时候系数为0
然后在状态
(A,B)
起始点的时候方程为
P(a,b)=p[a]∗p[b]∗P(a,b)+Out[u]∗p[b]∗P(u,b)+p[a]∗Out[v]∗P(a,v)+Out[u]∗Out[v]∗P(u,v)+1
高斯消元即可
#include <bits/stdc++.h>
#define maxn 10010
#define st(i, j) (i-1)*n+j
using namespace std;
int n, m;
int deg[maxn];
struct Edge{int to, next;}edge[maxn];
int h[maxn], cnt, s, t;
void add(int u, int v){
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
h[u] = cnt;
deg[u] ++;
}
double p[maxn], Out[maxn];
double a[510][510];
void Debug(int n){
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n + 1; j ++){
printf("%.2lf ", a[i][j]);
}printf("\n");
}puts("");
}
void build(int x, int y){
int now = st(x, y);
a[now][now] -= 1;
for(int i = h[x]; i; i = edge[i].next){
for(int j = h[y]; j; j = edge[j].next){
int u = edge[i].to, v = edge[j].to, to = st(u, v);
if(u != v){
if(u == x && v == y)a[now][to] += p[u] * p[v];
else if(u == x)a[now][to] += p[u] * Out[v];
else if(v == y)a[now][to] += Out[u] * p[v];
else a[now][to] += Out[u] * Out[v];
}
}
}
}
void Gauss(int n){
for(int i = 1; i <= n; i ++){
for(int j = i; j <= n; j ++)if(a[j][i]){
for(int k = 1; k <= n + 1; k ++)
swap(a[i][k], a[j][k]);
for(int k = 1; k <= n + 1; k ++)
if(k != i)a[i][k] /= a[i][i];
a[i][i] = 1;
break;
}
if(!a[i][i])continue;
for(int j = 1; j <= n; j ++){
if(j == i)continue;
double t = a[j][i];
for(int k = 1; k <= n + 1; k ++)
a[j][k] -= t * a[i][k];
}
}
}
int main(){
scanf("%d%d%d%d", &n, &m, &s, &t);
int u, v;
for(int i = 1; i <= m; i ++){
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
for(int i = 1; i <= n; i ++)
scanf("%lf", &p[i]);
for(int i = 1; i <= n; i ++)
Out[i] = (1 - p[i]) / deg[i];
for(int i = 1; i <= n; i ++) add(i, i);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
build(i, j);
a[st(s, t)][n * n + 1] = -1;
Gauss(n * n);
for(int i = 1; i <= n; i ++){
int now = st(i, i);
printf("%.6lf ", a[now][n * n + 1]);
}
return 0;
}