BZOJ1097 : [POI2007]旅游景点atr

状压DP新姿势get√

 

需要注意的是,这题Main上原题的内存限制只有64MB。

 

首先以2到k+1为起点进行k次dijkstra求出:

1.dis[i][j]:i到j的最短路

2.d1[i]:i到1的最短路

3.dn[i]:i到n的最短路

用二进制状态a[i]表示走到i之前必须经过的点的集合。

设f[z][S][i]表示现在走过的集合中有z个元素,现在走过的集合为S,最后走过的点是i的最短路,

则由f[z][S][i]可以向f[z+1][S|(1<<j)][j]扩展,扩展的条件是j不属于S,且S包含a[j]。

边界条件:f[1][1<<i][i]=a[i]==0?d1[i]:inf

最后ans=min(f[k][(1<<k)-1][i]+dn[i])

z这一维显然可以滚动,S这一维最多只有$C_k^{\lceil\frac{k}{2}\rceil}$种,所以先预处理出:

1.id[i]:i这个数在与它1的个数相同的数字中排第几

2.cnt[i]:有i个1的数字个数

3.st[i][j]:有i个1的数字中排第j的是哪个数

时间复杂度$O(kn\log n+n^2C_k^{\lceil\frac{k}{2}\rceil})$。

空间复杂度$O(nC_k^{\lceil\frac{k}{2}\rceil})$。

 

#include<cstdio>
const int N=20010,M=400010,K=20,Q=184756;
int n,m,k,i,j,S,E,U,x,y,z,d[N],dis[K][K],d1[K],dn[K],a[K],g[N],v[M],w[M],nxt[M],ed;
int id[1<<K],cnt[K],st[K][Q],f[2][Q][K],ans=1000000000;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void up(int&a,int b){if(a>b)a=b;}
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
struct PI{
  int x,y;
  PI(){}
  PI(int _x,int _y){x=_x,y=_y;}
  inline PI operator+(PI b){return x<b.x?PI(x,y):b;}
}val[65537];
void build(int x,int a,int b){
  val[x]=PI(ans,a);
  if(a==b)return;
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
inline void change(int x,int a,int b,int c,int d){
  if(a==b){val[x].x=d;return;}
  int mid=(a+b)>>1;
  c<=mid?change(x<<1,a,mid,c,d):change(x<<1|1,mid+1,b,c,d);
  val[x]=val[x<<1]+val[x<<1|1];
}
void dijkstra(int S){
  int i;
  for(i=1;i<=n;i++)d[i]=ans;
  build(1,1,n),change(1,1,n,S,d[S]=0);
  while(val[1].x<ans)for(change(1,1,n,x=val[1].y,ans),i=g[x];i;i=nxt[i])if(d[x]+w[i]<d[v[i]])change(1,1,n,v[i],d[v[i]]=d[x]+w[i]);
}
int main(){
  read(n),read(m),read(k);
  while(m--)read(x),read(y),read(z),add(x,y,z),add(y,x,z);
  if(!k)return dijkstra(1),printf("%d",d[n]),0;
  for(read(m);m--;a[y-2]|=1<<(x-2))read(x),read(y);
  for(i=2;i<=k+1;i++){
    for(dijkstra(i),j=2;j<=k+1;j++)dis[i-2][j-2]=d[j];
    d1[i-2]=d[1],dn[i-2]=d[n];
  }
  for(E=(1<<k)-1,S=1;S<=E;S++)id[S]=cnt[i=__builtin_popcount(S)-1],st[i][cnt[i]++]=S;
  for(x=0;x<cnt[0];x++)for(i=0;i<k;i++)f[0][x][i]=ans;
  for(i=0;i<k;i++)if(!a[i])f[0][id[1<<i]][i]=d1[i];
  for(z=y=0;z<k-1;z++,y^=1){
    for(x=0;x<cnt[z+1];x++)for(i=0;i<k;i++)f[y^1][x][i]=ans;
    for(x=0;x<cnt[z];x++)for(S=st[z][x],i=0;i<k;i++)if(f[y][x][i]<ans)for(U=E^S;U;U-=U&-U){
      j=__builtin_ctz(U&-U);
      if((S&a[j])==a[j])up(f[y^1][id[S|(1<<j)]][j],f[y][x][i]+dis[i][j]);
    }
  }
  for(i=0;i<k;i++)up(ans,f[y][0][i]+dn[i]);
  return printf("%d",ans),0;
}

  

posted @ 2015-06-29 16:01  Claris  阅读(542)  评论(0编辑  收藏  举报