BZOJ1757 : Apple 偷蘋果

Claris發表於2019-02-03

設$f0[i][j][x][y][S]$表示盜賊位於$(i,j)$,守衛位於$(x,y)$,每棵蘋果樹蘋果數量為$S$,盜賊先手時盜賊還能偷多少蘋果。

設$f1[i][j][x][y][S]$表示盜賊位於$(i,j)$,守衛位於$(x,y)$,每棵蘋果樹蘋果數量為$S$,守衛先手時盜賊還能偷多少蘋果。

轉移:$f0$為後繼$f1$狀態的最大值,$f1$為後繼$f0$狀態的最小值。

假設所有狀態的值都是$0$,將所有狀態加入佇列依次進行鬆弛,發現值改變則繼續入佇列。

因為每個狀態的值只有$13$種取值,所以最多入佇列$13$次。

 

#include<cstdio>
const int N=230500,M=1048575;
char a[9][9];
int Case,n,m,ca,cnt,i,j,k,x,y,nx,ny,S,sx,sy,tx,ty,o,tmp,flag;
int id[7][8][7][8][256],apple[7][8];
int f0[N],f1[N];bool in0[N],in1[N];
int head,tail,q[M+5];
bool can[7][8];
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int g0[N][12],g1[N][12],h0[N][12],h1[N][12];
inline int get(int x,int y){return x>>(y<<1)&3;}
inline int down(int x,int y){return x-(1<<(y<<1));}
inline void umin(int&a,int b){a>b?(a=b):0;}
inline void umax(int&a,int b){a<b?(a=b):0;}
inline void add01(int x,int y,int z){
  g0[x][++g0[x][0]]=y<<1|z;
  h1[y][++h1[y][0]]=x;
}
inline void add10(int x,int y){
  g1[x][++g1[x][0]]=y;
  h0[y][++h0[y][0]]=x;
}
inline void cal0(int x){
  int old=f0[x],now=0;
  for(int i=1;;i++){
    int u=g0[x][i];
    if(!u)break;
    umax(now,f1[u>>1]+(u&1));
  }
  if(now!=old){
    f0[x]=now;
    if(!in0[x])q[tail=(tail+1)&M]=x,in0[x]=1;
  }
}
inline void cal1(int x){
  int old=f1[x],now=12;
  for(int i=1;;i++){
    int u=g1[x][i];
    if(!u)break;
    umin(now,f0[u]);
  }
  if(now!=old){
    f1[x]=now;
    if(!in1[x])q[tail=(tail+1)&M]=-x,in1[x]=1;
  }
}
int main(){
  n=5,m=6;
  scanf("%d",&Case);
  while(Case--){
    for(i=0;i<=n+1;i++)for(j=0;j<=m+1;j++)can[i][j]=0,apple[i][j]=-1;
    ca=0;
    for(i=1;i<=n;i++){
      scanf("%s",a[i]+1);
      for(j=1;j<=m;j++){
        if(a[i][j]!='#')can[i][j]=1;
        if(a[i][j]=='3')apple[i][j]=ca++;
        if(a[i][j]=='S')sx=i,sy=j;
        if(a[i][j]=='T')tx=i,ty=j;
      }
    }
    cnt=0;
    for(i=0;i<=n+1;i++)for(j=0;j<=m+1;j++)for(x=0;x<=n+1;x++)for(y=0;y<=m+1;y++)for(S=0;S<256;S++)id[i][j][x][y][S]=0;
    for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(can[i][j])
      for(x=1;x<=n;x++)for(y=1;y<=m;y++)if(can[x][y]&&((x!=i)||(y!=j)))
        for(S=0;S<256;S++)id[i][j][x][y][S]=++cnt;
    for(i=0;i<=cnt;i++){
      f0[i]=f1[i]=0;
      g0[i][0]=g1[i][0]=h0[i][0]=h1[i][0]=0;
    }
    for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(can[i][j])
      for(x=1;x<=n;x++)for(y=1;y<=m;y++)if(can[x][y]&&((x!=i)||(y!=j)))
        for(S=0;S<256;S++){
          o=id[i][j][x][y][S];
          
          flag=0;
          tmp=apple[i][j];
          if(~tmp){
            if(get(S,tmp))add01(o,id[i][j][x][y][down(S,tmp)],1);
            else add01(o,o,0);
          }
          for(k=0;k<4;k++){
            nx=i+dx[k],ny=j+dy[k];
            if(!can[nx][ny]||(nx==x&&ny==y))continue;
            flag=1;
            tmp=apple[nx][ny];
            if(~tmp){
              if(get(S,tmp))add01(o,id[nx][ny][x][y][down(S,tmp)],1);
              else add01(o,id[nx][ny][x][y][S],0);
            }else add01(o,id[nx][ny][x][y][S],0);
          }
          if(!flag)add01(o,o,0);
          
          flag=0;
          tmp=apple[x][y];
          if(~tmp){
            if(get(S,tmp))add10(o,id[i][j][x][y][down(S,tmp)]);
            else add10(o,o);
          }
          for(k=0;k<4;k++){
            nx=x+dx[k],ny=y+dy[k];
            if(!can[nx][ny]||(nx==i&&ny==j))continue;
            flag=1;
            tmp=apple[nx][ny];
            if(~tmp){
              if(get(S,tmp))add10(o,id[i][j][nx][ny][down(S,tmp)]);
              else add10(o,id[i][j][nx][ny][S]);
            }else add10(o,id[i][j][nx][ny][S]);
          }
          if(!flag)add10(o,o);
        }
    for(i=1;i<=cnt;i++){
      g0[i][g0[i][0]+1]=0;
      g1[i][g1[i][0]+1]=0;
      h0[i][h0[i][0]+1]=0;
      h1[i][h1[i][0]+1]=0;
    }
    head=1,tail=cnt;
    for(i=1;i<=cnt;i++){
      in0[i]=0,in1[i]=1;
      q[i]=-i;
    }
    while(head!=(tail+1)&M){
      x=q[head];
      head=(head+1)&M;
      if(x>0){
        in0[x]=0;
        for(i=1;h0[x][i];i++)cal1(h0[x][i]);
      }else{
        x=-x;
        in1[x]=0;
        for(i=1;h1[x][i];i++)cal0(h1[x][i]);
      }
    }
    printf("%d\n",f0[id[tx][ty][sx][sy][255]]);
  }
  return 0;
}

  

相關文章