题面
https://darkbzoj.tk/problem/3270
题解
前置知识:
本题的正常做法见https://blog.csdn.net/aarongzk/article/details/51473258。
这里提供一种不正常的矩阵求逆方法。之所以说它不正常,是因为我自己都不能证明这个算法的正确性,但是它是能过题的(
设状态((t,u,v))表示当前时刻为t,两人分别处在位置u、v。设(f[t][u][v])表示从初始状态出发,能够到达状态((t,u,v))的概率。下记(q[u]=frac{1-p[u]}{deg[u]}),(link[u])表示u的相邻点集合,有转移方程如下:
[f[t][u][v] = egin{cases} f[t-1][u][v] imes p[u]p[v] \ sumlimits_{i in link[u],i
eq v}f[t-1][i][v] imes q[i]p[v] \ sumlimits_{j in link[v],j
eq u}f[t-1][u][j] imes p[u]q[j] \ sumlimits_{i in link[u],j in link[v],i
eq j}f[t-1][i][j] imes q[i]q[j] end{cases}
]
发现这个转移可以用矩阵描述。
[M imes left[ egin{matrix} f[t-1][1][1] \ f[t-1][1][2] \ vdots \f[t-1][n][n] end{matrix}
ight] = left[ egin{matrix} f[t][1][1] \ f[t][1][2] \ vdots \f[t][n][n] end{matrix}
ight]
]
其中转移矩阵M,是一个(n^2 imes n^2)的矩阵,可以通过上面的转移方程计算出来。
我们想计算出(F[u][v]=sum_{t=0}^{+ infty}f[t][u][v]),因为在u点相遇的答案就是(frac{F[u][u]}{sum_i f[i][i]})。而
[(E+M+M^2+…) imes left[ egin{matrix} f[0][1][1] \ f[0][1][2] \ vdots \f[0][n][n] end{matrix}
ight] = left[ egin{matrix} F[1][1] \ F[1][2] \ vdots \F[n][n] end{matrix}
ight]
]
显然(f[0][u][v] = [u=a] imes[v=b]);另外,(E+M+M^2+…)又可以化成(frac{E}{E-M}=(E-M)^{-1})
这样就做完了,总时间(O(n^6))
不过,这个算法有两个BUG:
- 无法证明(E-M)的行列式不等于0,因此((E-M)^{-1})不一定存在
- (E+M+M^2…)的收敛性无从证明,因此几何级数公式不一定适用
虽然这样做能过题,但是这两点仍未解决,欢迎在评论区发表见解~
代码
#include<bits/stdc++.h>
using namespace std;
#define ld long double
#define rg register
#define In inline
const int SN = 400;
const int N = 20;
const ld eps = 1e-9;
In int sgn(ld x){
return x < eps ? -1 : x > eps;
}
In int read(){
int s = 0,ww = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
return s * ww;
}
int n,m,sn;
In int id(int i,int j){
return (i - 1) * n + j;
}
struct mat{
ld d[SN+5][SN+5];
friend mat operator + (mat a,mat b){
for(rg int i = 1;i <= sn;i++)
for(rg int j = 1;j <= sn;j++)a.d[i][j] += b.d[i][j];
return a;
}
friend mat operator - (mat a,mat b){
for(rg int i = 1;i <= sn;i++)
for(rg int j = 1;j <= sn;j++)a.d[i][j] -= b.d[i][j];
return a;
}
friend mat operator * (mat a,mat b){
mat c;
for(rg int i = 1;i <= sn;i++)
for(rg int j = 1;j <= sn;j++)
for(rg int k = 1;k <= sn;k++)c.d[i][j] += a.d[i][k] * b.d[k][j];
return c;
}
void Swap(int i1,int i2){
for(rg int j = 1;j <= sn;j++)swap(d[i1][j],d[i2][j]);
}
void mul(int i,ld k){
for(rg int j = 1;j <= sn;j++)d[i][j] *= k;
}
void add(int i1,int i2,ld k){
for(rg int j = 1;j <= sn;j++)d[i1][j] += d[i2][j] * k;
}
}M,E;
mat inv(mat a){
mat b = E;
for(rg int j = 1;j <= sn;j++){
for(rg int i = j;i <= sn;i++)if(sgn(a.d[i][j]) != 0){
if(i != j)a.Swap(i,j),b.Swap(i,j);
break;
}
ld x = 1.0 / a.d[j][j];
a.mul(j,x),b.mul(j,x);
for(rg int i = j + 1;i <= sn;i++){
ld y = a.d[i][j];
a.add(i,j,-y),b.add(i,j,-y);
}
}
for(rg int j = sn;j >= 1;j--){
for(rg int i = 1;i < j;i++){
ld y = a.d[i][j];
a.add(i,j,-y),b.add(i,j,-y);
}
}
return b;
}
int head[N+5],deg[N+5],cnt;
struct edge{
int next,des;
}e[2*SN+5];
In void addedge(int a,int b){
cnt++;
deg[a]++;
e[cnt].des = b;
e[cnt].next = head[a];
head[a] = cnt;
}
ld p[N+5],q[N+5];
int main(){
int a,b;
scanf("%d%d%d%d",&n,&m,&a,&b);
sn = n * n;
for(rg int i = 1;i <= sn;i++)E.d[i][i] = 1;
for(rg int i = 1;i <= m;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
for(rg int i = 1;i <= n;i++){
double x;
scanf("%lf",&x);
p[i] = x;
q[i] = (1.0 - p[i]) / deg[i];
}
for(rg int u = 1;u <= n;u++)
for(rg int v = 1;v <= n;v++){
if(u != v)M.d[id(u,v)][id(u,v)] = p[u] * p[v];
for(rg int eu = head[u];eu;eu = e[eu].next){
int i = e[eu].des;
if(i != v)M.d[id(u,v)][id(i,v)] = q[i] * p[v];
}
for(rg int ev = head[v];ev;ev = e[ev].next){
int j = e[ev].des;
if(u != j)M.d[id(u,v)][id(u,j)] = p[u] * q[j];
}
for(rg int eu = head[u];eu;eu = e[eu].next){
for(rg int ev = head[v];ev;ev = e[ev].next){
int i = e[eu].des,j = e[ev].des;
if(i != j)M.d[id(u,v)][id(i,j)] = q[i] * q[j];
}
}
}
M = inv(E - M);
ld s = 0;
for(rg int i = 1;i <= n;i++)s += M.d[id(i,i)][id(a,b)];
for(rg int i = 1;i <= n;i++){
double p = M.d[id(i,i)][id(a,b)] / s;
printf("%.6lf",p);
putchar(i == n ? '
' : ' ');
}
return 0;
}