[bzoj3270] 博物馆
读入边的时候记录每个点的度d。
设f[x][y]为从开始到一个人在x,一个人在y的概率。
f[x][y]可以通过四种状态转移过来。
1.两个人都原地不动:通过f[x][y]自己转移过来,概率为p[x]*p[y]。
2.第一个人不动,第二个人从j过来(j和y有连边):通过f[x][j]转移,概率为p[x]*(1-p[j])/d[j]。
3.第二个人不动,第一个人从i过来(i和x有连边):通过f[i][y]转移,概率为p[y]*(1-p[i])/d[i]。
4.第一个人从i过来,第二个人从j过来(i与x、j与y均有连边):通过f[i][j]转移,概率为(1-p[i])*(1-p[j])*(d[i]*d[j])。
这样我们得到了状态转移方程。
可以看出任意两种状态(x,y)之间都能转移(没有连边的概率为0),只是概率不同。
这样总共n*n个状态,每个状态都得到一个方程,每个方程包含n*n个未知数。
上高斯消元求解。
最后对于x==y的状态进行输出。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n,s,m,a,b; 7 int e[25][25]; 8 int d[25]; 9 double ps[25]; 10 double k[405][405]; 11 double ans[405]; 12 13 int id(int x,int y) 14 { 15 return x*n-n+y; 16 } 17 18 double v(double rw) 19 { 20 return rw>0?rw:(-rw); 21 } 22 23 void cal(int x,int y) 24 { 25 int p=id(x,y); 26 k[p][p]=-1.00; 27 for(int i=1;i<=n;i++) 28 { 29 if(!e[i][x])continue; 30 for(int j=1;j<=n;j++) 31 { 32 if((!e[j][y])||(i==j))continue; 33 int q=id(i,j); 34 if(p==q)k[p][q]+=ps[i]*ps[j]; 35 else if(x==i)k[p][q]+=ps[i]*(1.0-ps[j])/(double)d[j]; 36 else if(y==j)k[p][q]+=ps[j]*(1.0-ps[i])/(double)d[i]; 37 else k[p][q]+=(1.0-ps[i])*(1.0-ps[j])/(double)(d[i]*d[j]); 38 } 39 } 40 } 41 42 void gauss() 43 { 44 for(int i=1;i<=s;i++) 45 { 46 int p=i; 47 for(int j=i+1;j<=s;j++) 48 if(v(k[j][i])>v(k[p][i]))p=j; 49 if(p!=i) 50 for(int j=i;j<=s+1;j++) 51 swap(k[p][j],k[i][j]); 52 double div=k[i][i]; 53 for(int j=i;j<=s+1;j++)k[i][j]/=div; 54 for(int j=i+1;j<=s;j++) 55 { 56 div=k[j][i]; 57 for(int l=i;l<=s+1;l++) 58 k[j][l]-=k[i][l]*div; 59 } 60 } 61 ans[s]=k[s][s+1]; 62 for(int i=s-1;i;i--) 63 { 64 ans[i]=k[i][s+1]; 65 for(int j=i+1;j<=s;j++) 66 ans[i]-=k[i][j]*ans[j]; 67 } 68 } 69 70 int main() 71 { 72 scanf("%d%d%d%d",&n,&m,&a,&b); 73 s=n*n; 74 for(int i=1;i<=m;i++) 75 { 76 int ff,tt; 77 scanf("%d%d",&ff,&tt); 78 e[ff][tt]=e[tt][ff]=1; 79 d[ff]++;d[tt]++; 80 } 81 for(int i=1;i<=n;i++)scanf("%lf",&ps[i]),e[i][i]=1; 82 k[id(a,b)][s+1]=-1.00; 83 for(int i=1;i<=n;i++) 84 for(int j=1;j<=n;j++) 85 cal(i,j); 86 gauss(); 87 for(int i=1;i<=n;i++)printf("%.6lf ",ans[id(i,i)]); 88 return 0; 89 }