CF113D Museum
题意:
一张联通图,每个结点 $i$ 有一个概率 $p[i]$,当一个人在上面的时候,有 $p[i]$ 概率停留,初始时有两人分别在 $a$,$b$,问他们在每个点相遇的概率是多少。
Solution:
定义状态 $f(i,j)$ 代表一人在 $i$,一人在 $j$ 的概率,然后得到转移方程
$f(i,j)=p_{i} \times p_{j} \times f(i,j) + \sum_{u\in son(i),u!=j}^{} \frac{(1-p(u))\times p(j) \times f(u,j)}{\left | son(u) \right | } +\sum_{u\in son(j),u!=i}^{}\frac{(1-p(u)) \times p(i) \times f(i,u)}{\left | son(u) \right |} + \sum_{u\in son(i),v\in son(j),u!=v}^{} \frac {(1-p(u))\times(1-p(v))\times f(u,v)}{\left | son(u) \right | \left | son(v) \right |} $然后你发现,起点的 $f(a,b)$ 等于上面那个式子加一,因为一开始的缘故。
然后你又发现,这些状态相互影响,但可以解方程!所以高斯消元,给每个点对一个下标作为一个元素,然后大力消元解方程,最后答案就是每个对角线上点对对应的答案。
code :
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i<(b);++i) #define rrep(i,a,b) for(int i=(a);i>=(b);--i) using namespace std; template <typename T> inline void read(T &x){ x=0;char ch=getchar();bool f=0; while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(f)x=-x; } template <typename T,typename ...Args> inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);} const int N = 22 * 22 + 5; int n,m,id[N][N],aa,b,d[N]; double a[N][N],p[N]; vector<int>g[N]; #define pb push_back signed main(){ read(n,m,aa,b); rep(i,1,m){ int u,v; read(u,v); g[u].pb(v); g[v].pb(u); ++d[u],++d[v]; } rep(i,1,n)scanf("%lf",&p[i]); m = 0; rep(i,1,n)rep(j,1,n)id[i][j] = ++m; a[id[aa][b]][m+1] = -1;//起点概率为1 rep(i,1,n)rep(j,1,n){ int x = id[i][j]; //f(i,j) = p[i] * p[j] * f[i][j] //f(i,j) * (p[i] * p[j] - 1) = 0 //i == j不存在停留 a[x][x] --; if(i != j)a[x][x] += p[i] * p[j]; for(int u : g[i])for(int v : g[j]){ if(v == u)continue; a[x][id[u][v]] = (1 - p[u]) * (1 - p[v]) / d[u] / d[v]; }//from(u,v) -> (i,j) for(int u : g[i]){ if(u == j)continue; a[x][id[u][j]] = (1 - p[u]) * p[j] / d[u]; }//from(u,j) -> (i,j) for(int u : g[j]){ if(u == i)continue; a[x][id[i][u]] = (1 - p[u]) * p[i] / d[u]; }//from(i,u) -> (i,j) } //gauss rep(i,1,m){//主元 int mx = i; rep(j,i+1,m){ if(fabs(a[j][i]) > fabs(a[mx][i])){ mx = j; } } rep(j,1,m+1)swap(a[i][j],a[mx][j]); rep(j,1,m){//行 if(j == i)continue; double K = a[j][i] / a[i][i];//系数 rep(k,i+1,m+1){ a[j][k] -= a[i][k] * K;//减去 } } } rep(i,1,n)printf("%.10lf ", a[id[i][i]][m+1] / a[id[i][i]][id[i][i]]); }