[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 }

猜你喜欢

转载自www.cnblogs.com/eternhope/p/9720276.html