【期望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 }

 

posted @ 2016-07-29 10:42  iiyiyi  阅读(165)  评论(0编辑  收藏  举报