【期望DP+高斯消元】BZOJ3270-博物馆
【题目大意】
有m条走廊连接的n间房间,并且满足可以从任何一间房间到任何一间别的房间。两个男孩现在分别处在a,b两个房间,每一分钟有Pi 的概率在这分钟内不去其他地方(即呆在房间不动),有1-Pi 的概率他会在相邻的房间中等可能的选择一间并沿着走廊过去。求两人在每间房间相遇的概率。
【思路】
向用链表把图建出来,建立的时候不要忘记了自己向自己再加一条边(见下面情况1)
我们将男孩A位于x,男孩B位于y的状态定义为id[x][y]。由id[tx][ty]状态转移到id[i][j]状态的概率。如果当前已经知道了抵达id[i][j]状态的期望概率为F[i,j]。
考虑以下几种可能性:
(1)tx=i且ty=j,说明两者都停留在原地不动,概率为Ptx*Pty*F[i,j];
(2)tx=i且ty≠j,说明男孩B移动了而男孩A没有,概率为Ptx*((1-Pty)/Dty)*F[i,ty],其中Dty为ty的出度;
(3)tx≠i且ty=j,概率为Pty*((1-Ptx)/Dtx)*F[tx,j];
(4)tx≠i且ty≠j,概率为((1-Ptx)/Dtx)*F[i,ty]*((1-Pty)/Dty)*F[tx,j]。
我们把F看成是未知数,它们前面乘上的看作是系数,对于F[i,j]可以列出以下方程:
F[i,j]=情况(1)+情况(2)+情况(3)+情况(4)。
0=(Ptx*Pty-1)*F[i,j]+情况(2)+情况(3)+情况(4)……(*)
如上 (*)式子总共可以列出n*n个。有一个特例是在其实位置,也就是F(a,b),由于一开始就位于id[a][b],也就是说初始时概率就为1了,所以在(*)右边还要加上1,移到等式左边就变成了-1,所以有a[id[aa][bb]][n*n+1]=-1。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<cmath> 7 using namespace std; 8 const int MAXN=20+5; 9 double f[MAXN*MAXN][MAXN*MAXN],p[MAXN]; 10 int id[MAXN][MAXN]; 11 vector<int> E[MAXN]; 12 double a[MAXN*MAXN][MAXN*MAXN]; 13 int n,m,aa,bb; 14 15 void init() 16 { 17 scanf("%d%d%d%d",&n,&m,&aa,&bb); 18 int cnt=0; 19 for (int i=1;i<=n;i++) 20 for (int j=1;j<=n;j++) id[i][j]=++cnt; 21 a[id[aa][bb]][n*n+1]=-1; 22 for (int i=1;i<=n;i++) E[i].push_back(i);//不要忘记把自己向自己是可以走的 23 for (int i=1;i<=m;i++) 24 { 25 int u,v; 26 scanf("%d%d",&u,&v); 27 E[u].push_back(v); 28 E[v].push_back(u); 29 } 30 for (int i=1;i<=n;i++) scanf("%lf",&p[i]); 31 } 32 33 void buildequ() 34 { 35 for (int i=1;i<=n;i++) 36 for (int j=1;j<=n;j++) 37 { 38 a[id[i][j]][id[i][j]]--;//位于方程右边系数为1,移到左边系数变成-1 39 for (int x=0;x<E[i].size();x++) 40 for (int y=0;y<E[j].size();y++) 41 { 42 int tx=E[i][x],ty=E[j][y]; 43 int fr=id[i][j],to=id[tx][ty]; 44 if (tx!=ty) 45 { 46 if (tx==i && ty==j) a[fr][to]+=p[tx]*p[ty];//停留在原地不动 47 else if (tx==i) a[fr][to]+=p[tx]*(1-p[ty])/(E[ty].size()-1); 48 else if (ty==j) a[fr][to]+=p[ty]*(1-p[tx])/(E[tx].size()-1); 49 else a[fr][to]+=(1-p[tx])*(1-p[ty])/(E[ty].size()-1)/(E[tx].size()-1); 50 } 51 } 52 } 53 } 54 55 void guass() 56 { 57 for (int i=1;i<=n*n;i++) 58 { 59 int t=i; 60 for (int j=i+1;j<=n*n;j++) if (fabs(a[j][i])>fabs(a[t][i])) t=j; 61 if (t!=i) for (int j=i;j<=n*n+1;j++) swap(a[i][j],a[t][j]);//不要忘记要到n*n+1 62 for (int j=i+1;j<=n*n;j++) 63 { 64 double x=a[j][i]/a[i][i]; 65 for (int k=i;k<=n*n+1;k++) a[j][k]-=a[i][k]*x; 66 } 67 } 68 for (int i=n*n;i>=1;i--) 69 { 70 for (int j=i+1;j<=n*n;j++) a[i][n*n+1]-=a[i][j]*a[j][n*n+1]; 71 a[i][n*n+1]/=a[i][i]; 72 } 73 } 74 75 void printans() 76 { 77 for (int i=1;i<=n;i++) printf("%.6lf ",a[id[i][i]][n*n+1]); 78 } 79 80 int main() 81 { 82 init(); 83 buildequ(); 84 guass(); 85 printans(); 86 return 0; 87 }