BZOJ1401 : Hexagon

Claris發表於2014-12-07

這題顯然是一個最小斯坦納樹的模型,直接上模板即可,就是正六邊形比較噁心。

 

#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;
}