BZOJ 3270 && BZOJ 1778 (期望DP && 高斯消元)


BZOJ 3270 :設置狀態為Id(x,y)表示一人在x,一人在y這個狀態的概率。 所以總共有n^2種狀態。

p[i]表示留在該點的概率,Out[i]=(1-p[i])/Degree[i]表示離開該點的概率.

那么對於每一種狀態a,b 則有P(a,b)=p[a]p[b]P(a,b)+Out[u]p[b]P(u,b)+p[a]Out[v]P(a,v)+Out[u]Out[v]P(u,v) 則有n^2個方程

對於起始狀態a,b,則有P(a,b)=p[a]p[b]P(a,b)+Out[u]p[b]P(u,b)+p[a]Out[v]P(a,v)+Out[u]Out[v]P(u,v)+1

 1  
2 #include <cstdio>
3 #include <cstring>
4 const int Maxn=10010;
5 double p[Maxn],Out[Maxn],a[510][510];
6 int Degree[Maxn],n,m,head[Maxn],cnt,s,t,u,v;
7 struct Edge{int to,next;}edge[Maxn<<1];
8 inline void Add(int u,int v)
9 {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
10 inline int Id(int x,int y) {return (x-1)*n+y;}
11 inline void Swap(double &x,double &y) {double t=x;x=y;y=t;}
12 void Build(int x,int y)
13 {
14 int S=Id(x,y);
15 a[S][S]-=1;
16 for (int i=head[x];i!=-1;i=edge[i].next)
17 for (int j=head[y];j!=-1;j=edge[j].next)
18 {
19 int u=edge[i].to,v=edge[j].to,T=Id(u,v);
20 if (u!=v)
21 {
22 if (u==x && v==y) a[S][T]+=p[u]*p[v];
23 else if (u==x) a[S][T]+=p[u]*Out[v];
24 else if (v==y) a[S][T]+=Out[u]*p[v];
25 else a[S][T]+=Out[u]*Out[v];
26 }
27 }
28 }
29 inline void Guass(int n)
30 {
31 for (int i=1;i<=n;i++)
32 {
33 for (int j=i;j<=n;j++)
34 if (a[j][i])
35 {
36 for (int k=1;k<=n+1;k++) Swap(a[i][k],a[j][k]);
37 for (int k=1;k<=n+1;k++) if (k!=i) a[i][k]/=a[i][i];
38 a[i][i]=1;
39 break;
40 }
41 if (!a[i][i]) continue;
42 for (int j=1;j<=n;j++)
43 {
44 if (j==i) continue;
45 double t=a[j][i];
46 for (int k=1;k<=n+1;k++) a[j][k]-=t*a[i][k];
47 }
48 }
49 }
50 int main()
51 {
52 scanf("%d%d%d%d",&n,&m,&s,&t);
53 memset(head,-1,sizeof(head));
54 for (int i=1;i<=m;i++)
55 {
56 scanf("%d%d",&u,&v);
57 Add(u,v),Add(v,u);
58 Degree[u]++,Degree[v]++;
59 }
60 for (int i=1;i<=n;i++) scanf("%lf",&p[i]);
61 for (int i=1;i<=n;i++) Out[i]=(1-p[i])/Degree[i];
62 for (int i=1;i<=n;i++) Add(i,i);
63 for (int i=1;i<=n;i++)
64 for (int j=1;j<=n;j++) Build(i,j);
65 a[Id(s,t)][n*n+1]=-1;
66 Guass(n*n);
67 for (int i=1;i<=n;i++) printf("%.6lf ",a[Id(i,i)][n*n+1]);
68 return 0;
69 }
C++

 BZOJ 1778:和上面的題目差不多但是要注意的是自己不可能轉移到自己因為要么炸要么移動

P(u)=Out(v)*P(v) 特別的 P(1)=Out(v)*P(v)+P/Q然后高斯消元即可.

 1 #include <cstdio>
2 #include <cmath>
3 #include <cstring>
4 #define LD long double
5 const int Maxn=510;
6 const int Maxm=50100;
7 const LD eps=1e-13;
8 int Degree[Maxn],head[Maxn],n,m,P,Q,cnt,u,v;
9 LD a[Maxn][Maxn],t,Out[Maxn];
10 struct Edge{int to,next;}edge[Maxm<<2];
11 inline void Swap(LD &x,LD &y) {LD t=x;x=y;y=t;}
12 inline int dcmp(LD x) {if (fabs(x)<eps) return 0; return (x>0)?1:-1;}
13 inline void Add(int u,int v)
14 {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
15 inline void Build(int u)
16 {
17 a[u][u]=1.0;
18 for (int i=head[u];i!=-1;i=edge[i].next)
19 a[u][edge[i].to]=-Out[edge[i].to];
20 }
21 inline void Gauss()
22 {
23 for (int i=1;i<=n;i++)
24 {
25 for (int j=i;j<=n;j++)
26 if (dcmp(a[i][j])!=0)
27 {
28 for (int k=1;k<=n+1;k++) Swap(a[i][k],a[j][k]);
29 for (int k=1;k<=n+1;k++) if (k!=i) a[i][k]/=a[i][i];
30 a[i][i]=1;
31 break;
32 }
33 if (dcmp(a[i][i])==0) continue;
34 for (int j=1;j<=n;j++)
35 {
36 if (j==i) continue;
37 LD t=a[j][i];
38 for (int k=1;k<=n+1;k++) a[j][k]-=t*a[i][k];
39 }
40 }
41 }
42 int main()
43 {
44 scanf("%d%d%d%d",&n,&m,&P,&Q); t=(LD)P/(LD)Q; t=1.0-t;
45 memset(head,-1,sizeof(head)); cnt=0;
46 for (int i=1;i<=m;i++)
47 {
48 scanf("%d%d",&u,&v);
49 Add(u,v),Add(v,u),Degree[u]++,Degree[v]++;
50 }
51
52 for (int i=1;i<=n;i++) Out[i]=t/(LD)Degree[i];
53 for (int i=1;i<=n;i++) Build(i);
54 a[1][n+1]=1-t;
55 Gauss();
56 for (int i=1;i<=n;i++) printf("%.9Lf\n",a[i][n+1]);
57 return 0;
58 }
C++

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com