题意:
两个人在图上走,每个点有 pi p i 的概率留在原地,其它等概率去一个相邻的点,直到相遇为止。问在每个点相遇的概率。
题意:
等价于求到某个点的期望值。
设
f[i][j]
f
[
i
]
[
j
]
表示一个人在i一个人在j的次数的期望值,然后列出转移方程,高斯消元即可。
注意不能从
i=j
i
=
j
的点转移过来,因为已经停止了。
code:
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,A,B,deg[25];
long double p[25];
struct node{
int y,next;
}a[450];int len=0,last[25];
long double g[410][410];
void ins(int x,int y)
{
a[++len].y=y;
a[len].next=last[x];last[x]=len;
}
int num[25][25];
const long double eps=1e-10;
void guass()
{
for(int i=1;i<=n*n;i++)
{
if(abs(g[i][i])<=eps)
{
for(int j=i+1;j<=n*n;j++)
if(abs(g[j][i])>eps)
{
for(int k=1;k<=n*n;k++) swap(g[i][k],g[j][k]);
break;
}
}
for(int j=i+1;j<=n*n;j++)
if(abs(g[j][i])>eps)
{
long double t=g[j][i]/g[i][i];
for(int k=i;k<=n*n+1;k++) g[j][k]-=t*g[i][k];
}
}
for(int i=n*n;i>=1;i--)
{
for(int j=i+1;j<=n*n;j++)
g[i][n*n+1]-=g[i][j]*g[j][n*n+1];
g[i][n*n+1]/=g[i][i];
}
}
int cnt=0;
int main()
{
scanf("%d %d %d %d",&n,&m,&A,&B);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
num[i][j]=++cnt;
for(int i=1;i<=m;i++)
{
int x,y;scanf("%d %d",&x,&y);
deg[x]++;deg[y]++;ins(x,y);ins(y,x);
}
for(int i=1;i<=n;i++) scanf("%Lf",&p[i]);
for(int x1=1;x1<=n;x1++)
for(int x2=1;x2<=n;x2++)
{
int s1=num[x1][x2];
g[s1][s1]=-1.0;
if(x1!=x2) g[s1][s1]+=p[x1]*p[x2];//两个都停在原地
for(int i=last[x1];i;i=a[i].next)
{
int y1=a[i].y,s3=num[y1][x2];
if(y1==x2) continue;
g[s1][s3]+=(1.0-p[y1])*p[x2]/(long double)(deg[y1]);
}
for(int j=last[x2];j;j=a[j].next)
{
int y2=a[j].y,s2=num[x1][y2];
if(x1==y2) continue;
g[s1][s2]+=(1.0-p[y2])*p[x1]/(long double)(deg[y2]);
}
for(int i=last[x1];i;i=a[i].next)
for(int j=last[x2];j;j=a[j].next)
{
int y1=a[i].y,y2=a[j].y,s4=num[y1][y2];
if(y1==y2) continue;
g[s1][s4]+=(1.0-p[y2])*(1.0-p[y1])/(long double)(deg[y1])/(double)(deg[y2]);
}
}
g[num[A][B]][n*n+1]=-1.0;
guass();
for(int i=1;i<=n;i++) printf("%.6Lf ",g[num[i][i]][n*n+1]);
}