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;

}

  

你可能感兴趣的:(2007)