BZOJ 3270 博物馆 && CodeForces 113D. Museum 期望概率dp 高斯消元

大前提,把两个点的组合看成一种状态 x

两种思路 O(n^7) f[x]表示在某一个点的前提下,这个状态经过那个点的概率,用相邻的点转移状态,高斯一波就好了

               O(n^6) 想象成臭气弹,这个和那个的区别只是状态维数变化,f[x]表示这个状态出现的概率,高斯一下就好了

我比较傻只想出来O(n^7)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef double D;
D a[400][400],source[400][400],ans[50],keep[50],get[500],sz;
int via[50][50],need,map[400000];
int n,m,Petya,Vasya;
inline int hash(int x,int y)
{
  if(x>y)x^=y^=x^=y;
  int gg=x*100+y;
  if(map[gg]==0)map[gg]=++sz;
  return map[gg];
}
inline D abs(D x)
{
  return x<0.0?0.0-x:x;
}
void gause()
{
    for(int i=1,k=1;i<=need&&k<=need;i++,k++)
    {
       int temp=i;
       D h=abs(a[i][k]);
       for(int j=i+1;j<=need;j++)
       if(h<abs(a[j][k]))
       {
         temp=j;
         h=abs(a[j][k]);
       }
       if(temp!=i)
       {
         for(int j=k;j<=need+1;j++)
          swap(a[i][j],a[temp][j]);
       }
       for(int j=i+1;j<=need;j++)
       {
          h=a[j][k]/a[i][k];
          for(int l=k;l<=need+1;l++)
           a[j][l]-=h*a[i][l];
       }
    }
    for(int i=need;i>0;i--)
    {
      for(int j=i+1;j<=need;j++)
        a[i][need+1]-=a[i][j]*get[j];
      get[i]=a[i][need+1]/a[i][i];
    }
}
void blabla(int x)
{
  for(int i=0;i<400;i++)
   for(int j=0;j<400;j++)
    a[i][j]=source[i][j];
  a[hash(x,x)][need+1]=1.0;
  gause();
  ans[x]=get[hash(Petya,Vasya)];
}
void pre()
{
    scanf("%d%d%d%d",&n,&m,&Petya,&Vasya);
    for(int i=1;i<=m;i++)
    {
      int x,y;
      scanf("%d%d",&x,&y);
      via[x][++via[x][0]]=y;
      via[y][++via[y][0]]=x;
    }
    need=n*(n+1)/2;
    for(int i=1;i<=n;i++)
     scanf("%lf",&keep[i]);
    for(int i=1;i<=n;i++)
     for(int j=i;j<=n;j++)
     {
       int x=hash(i,j);
       if(i==j)
       {
          source[x][x]=1.0;
          continue;
       }
       D Viai=1.0*via[i][0],Viaj=1.0*via[j][0];
       D Keep=(1.0-keep[i])*(1.0-keep[j])/Viai/Viaj;
       for(int z=1;z<=via[i][0];z++)
        for(int y=1;y<=via[j][0];y++)
         source[x][hash(via[i][z],via[j][y])]+=Keep;
       Keep=(1.0-keep[i])*keep[j]/Viai;
       for(int z=1;z<=via[i][0];z++)
         source[x][hash(via[i][z],j)]+=Keep;
       Keep=(1.0-keep[j])*keep[i]/Viaj;
       for(int y=1;y<=via[j][0];y++)
         source[x][hash(via[j][y],i)]+=Keep;
       source[x][x]+=keep[i]*keep[j];
       source[x][x]-=1.0;
     }
}
void work()
{
    ans[n]=1.0;
    for(int i=1;i<n;i++)
    {
     blabla(i);
     ans[n]-=ans[i];
    }
}
void print()
{
    for(int i=1;i<=n;i++)
     printf("%.10lf ",ans[i]);
}
int main()
{
    pre();
    work();
    print();
}

 

posted @ 2017-06-28 09:09  TS_Hugh  阅读(355)  评论(0编辑  收藏  举报