BZOJ1401 : Hexagon

这题显然是一个最小斯坦纳树的模型,直接上模板即可,就是正六边形比较恶心。

 

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<queue>

#define rep(i,n) for(int i=0;i<n;i++)

#define INF 0x3f3f3f3f

using namespace std;

const int N=1610,M=9610;

typedef pair<int,int>P;

int R,n,m,k=4,f[N][1<<4],st[N],all=1<<k,ans,g[N],to[M],nxt[M],cost[N],e,id[41][41];

bool vis[N][1<<4];

queue<int>Q;

int read(){

  char ch;

  while(!(((ch=getchar())=='A')||(ch=='B')||(ch=='C')||(ch=='D')||(ch=='.')));

  return ch=='.'?4:ch-'A';

}

void add(int u,int v){to[e]=v;nxt[e]=g[u];g[u]=e++;}

void add(int u,int x,int y){

  if(x<0||y<0||x>=m||y>=m)return;

  if(~id[x][y]&&id[x][y]!=u)add(u,id[x][y]);

}

void spfa(int S){

  while(!Q.empty()){

    int u=Q.front();Q.pop();

    vis[u][S]=false;

    for(int p=g[u];~p;p=nxt[p]){

      int v=to[p];

      int w=cost[v];

      if(f[v][st[v]|S]>f[u][S]+w){

        f[v][st[v]|S]=f[u][S]+w;

        if(st[v]|S!=S||vis[v][S])continue;

        vis[v][S]=1;

        Q.push(v);

      }

    }

  }

}

void solve(){

  memset(g,-1,sizeof g);

  while(!Q.empty())Q.pop();

  e=0;n=k;m=R*2-1;

  rep(i,m)rep(j,m)id[i][j]=-1;

  rep(i,R-1)rep(j,R+i){

    int x=read();

    if(x<k)cost[id[i][j]=x]=0;else cost[id[i][j]=n++]=1;

  }

  rep(i,R)rep(j,m-i){

    int x=read();

    if(x<k)cost[id[R+i-1][j]=x]=0;else cost[id[R+i-1][j]=n++]=1;

  }

  rep(i,m)rep(j,m)if(~id[i][j]){

    add(id[i][j],i,j-1);

    add(id[i][j],i,j+1);

    if(i<R-1){

      add(id[i][j],i-1,j-1);

      add(id[i][j],i-1,j);

      add(id[i][j],i+1,j);

      add(id[i][j],i+1,j+1);

    }else if(i==R-1){

      add(id[i][j],i-1,j-1);

      add(id[i][j],i-1,j);

      add(id[i][j],i+1,j-1);

      add(id[i][j],i+1,j);

    }else{

      add(id[i][j],i-1,j);

      add(id[i][j],i-1,j+1);

      add(id[i][j],i+1,j-1);

      add(id[i][j],i+1,j);

    }

  }

  rep(i,n)rep(j,all)f[i][j]=INF;

  memset(st,0,sizeof st);

  memset(vis,0,sizeof vis);

  rep(i,k)st[i]=1<<i,f[i][st[i]]=0;

  for(int j=1;j<all;j++){

    rep(i,n){

      if(st[i]&&(st[i]&j)==0)continue;

      for(int sub=(j-1)&j;sub;sub=(sub-1)&j){

        int x=st[i]|sub,y=st[i]|(j-sub);

        f[i][j]=min(f[i][j],f[i][x]+f[i][y]-cost[i]);

      }

      if(f[i][j]<INF){

        Q.push(i);

        vis[i][j]=true;

      }

    }

    spfa(j);

  }

  ans=INF;

  rep(j,n)ans=min(ans,f[j][all-1]);

  printf("You have to buy %d parcels.\n",ans);

}

int main(){

  while(scanf("%d",&R),R)solve();

  return 0;

}

  

 

你可能感兴趣的:(ZOJ)