BZOJ3836 : [Poi2014]Tourism

对于一个连通块,取一个点进行dfs,得到一棵dfs搜索树,则这棵树的深度不超过10,且所有额外边都是前向边。

对于每个点x,设S为三进制状态,S第i位表示根到x路径上深度为i的点的状态:

0:选了

1:没选,且没满足

2:没选,且已满足

设f[i][j]表示考虑根到x路径上深度为i的点时这些点的状态为j时的最小费用,然后按DFS序进行DP即可。

时间复杂度$O((n+m)3^{10})$,空间复杂度$O(10\times3^{10})$。

 

#include<cstdio>
const int N=20010,M=50010,K=11,inf=2000000000;
int n,m,i,x,y,a[N],g[N],v[M],nxt[M],ed,vis[N],d[N],q[K],pow[K],f[K][59050],ans;
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline int bit(int x,int y){return x/pow[y]%3;}
inline void up(int&x,int y){if(x>y)x=y;}
inline int min(int x,int y){return x<y?x:y;}
void dfs(int x,int y){
  vis[x]=1,d[x]=y;
  if(!y)f[0][0]=a[x],f[0][1]=0,f[0][2]=inf;
  else{
    int cnt=0;
    for(int i=g[x];i;i=nxt[i]){
      int u=v[i];
      if(vis[u]&&d[u]<y)q[cnt++]=d[u];
    }
    for(int S=pow[y+1]-1;~S;S--)f[y][S]=inf;
    for(int S=pow[y]-1;~S;S--){
      int U=1,V=S;
      for(int i=0;i<cnt;i++)if(bit(S,q[i])==0)U=2;else if(bit(S,q[i])==1)V+=pow[q[i]];
      up(f[y][S+U*pow[y]],f[y-1][S]);
      up(f[y][V],f[y-1][S]+a[x]);
    }
  }
  for(int i=g[x];i;i=nxt[i]){
    int u=v[i];
    if(!vis[u]){
      dfs(u,y+1);
      for(int S=0;S<pow[y+1];S++)f[y][S]=min(f[y+1][S],f[y+1][S+2*pow[y+1]]);
    }
  }
}
int main(){
  for(pow[0]=i=1;i<K;i++)pow[i]=pow[i-1]*3;
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++)scanf("%d",&a[i]);
  while(m--)scanf("%d%d",&x,&y),add(x,y),add(y,x);
  for(i=1;i<=n;i++)if(!vis[i])dfs(i,0),ans+=min(f[0][0],f[0][2]);
  return printf("%d",ans),0;
}

  

posted @ 2015-10-05 02:52  Claris  阅读(862)  评论(0编辑  收藏  举报