Description
Input
Output
Sample Input
1 2
0.5
0.5
Sample Output
HINT
对于100%的数据有 n <= 20,n-1 <= m <= n(n-1)/2
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~高斯消元~
根据题目建图,同时记录每个点的度数du[i]。
我们把两人走的点记在同一个数组a[k][k]中,状态k=d(i,j)表示A在i点,B在j点。
每个点输入的概率为gl[i],走到它的相邻点的概率就是(1.0-gl[i])/(double)du[i]。
用a[i][j]表示关于状态i的方程中状态j的系数,那么我们就需要找出状态之间的关系。设z[d(i,j)]表示状态d(i,j)的期望到达次数,则
z[d(i,j)]=z[d(i,j)]*gl[i]*gl[j]+z[d(kkz1,j)]*gl[j]*k[kkz1](kkz1与i直接相连)+z[d(i,kkz2)]*gl[i]*k[kkz2](kkz2与j直接相连)+z[d(kkz1,kkz2)]*k[kkz1]*k[kkz2]。
然后把z[d(i,j)]移到右面即成为一个方程。同理我们可以列出n个方程,显然有唯一解。
要注意的是因为是从d(a,b)出发的,所以d(a,b)要有一个常数项1,移项后变为-1。
另外,d(i,i)是不能用于转移其他状态的,因为两人相遇后就停止游荡,这里要特判一下~
#include<cstdio>
#define d(u,v) (u+(v-1)*n)
int n,m,x,y,aa,bb,du[21],w[401],ne[401],fi[21],cnt;
double gl[21],a[401][402],k[21];
int read()
{
int totnum=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {totnum=(totnum<<1)+(totnum<<3)+ch-'0';ch=getchar();}
return totnum*f;
}
void add(int u,int v)
{
w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;
w[++cnt]=u;ne[cnt]=fi[v];fi[v]=cnt;
}
void guass(int n)
{
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n+1;j++) a[i][j]/=a[i][i];a[i][i]=1;
for(int j=i+1;j<=n;j++)
{
for(int k=i+1;k<=n+1;k++) a[j][k]-=a[j][i]*a[i][k];
a[j][i]=0;
}
}
for(int i=n;i>1;i--)
{
for(int j=i+1;j<=n+1;j++) a[i][j]/=a[i][i];a[i][i]=1;
for(int j=i-1;j;j--)
{
for(int k=i+1;k<=n+1;k++) a[j][k]-=a[j][i]*a[i][k];
a[j][i]=0;
}
}
}
int main()
{
n=read();m=read();aa=read();bb=read();
for(int i=1;i<=m;i++)
{
x=read(),y=read();add(x,y);du[x]++,du[y]++;
}
for(int i=1;i<=n;i++) scanf("%lf",&gl[i]),k[i]=(1.0-gl[i])/(double)du[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
a[d(i,j)][d(i,j)]-=1.0;
if(i!=j) a[d(i,j)][d(i,j)]+=gl[i]*gl[j];
for(int z=fi[j];z;z=ne[z]) if(i!=w[z]) a[d(i,j)][d(i,w[z])]+=gl[i]*k[w[z]];
for(int z=fi[i];z;z=ne[z]) if(j!=w[z]) a[d(i,j)][d(w[z],j)]+=k[w[z]]*gl[j];
for(int z=fi[i];z;z=ne[z])
for(int r=fi[j];r;r=ne[r]) if(w[z]!=w[r]) a[d(i,j)][d(w[z],w[r])]+=k[w[z]]*k[w[r]];
}
a[d(aa,bb)][n*n+1]+=-1.0;
guass(n*n);
for(int i=1;i<=n;i++) printf("%.6lf ",a[d(i,i)][n*n+1]);
return 0;
}