BZOJ 3270 && BZOJ 1778 (期望DP && 高斯消元)
Posted on 2016-07-25 11:04 yyjxx2010xyu 阅读(109) 评论(0) 编辑 收藏 举报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 }
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 }