【GDOI2015】 推箱子 状态压缩+bfs
请注意$8$是一个美妙的数字
考虑到$8\times 8=64$,而一个unsigned long long是$64$位的,所以考虑用一个$01$状态存储箱子。考虑到箱子能转动,那么四种情况都存一下就可以了。
为了能够快速判断某个位置是否可以放下箱子,我们令$f[i][j]$表示左上角为$(i,j)$,大小为$m\times m$的矩形内的$01$状态。
若箱子可以呆在左上角为$(i,j)$的矩形里,那么箱子的状态值$\&f[i][j]$必然为$0$。
令$dis[i][j][k]$表示箱子当前跑到$(i,j)$,逆时针转动的角度为$k\times90$度的最少步数。
发现这是一个网格图,且边权都是$1$,直接随便转移一下就好了。
时间复杂度:O(4n^2+n^2m)。 但是下方的代码是O(4n^2+n^2m^2)的,似乎问题不大。
1 #include<bits/stdc++.h> 2 #define M 2005 3 #define L unsigned long long 4 using namespace std; 5 int INF; 6 char c[100]={0},ch[M][M]={0}; 7 int n,m,box[8][8]={0},Box[8][9]={0},dis[M][M][4]={0}; 8 L b[4]={0},a[M][M]={0}; 9 10 void rotate(){ 11 for(int i=0;i<m;i++) 12 for(int j=0;j<m;j++) 13 Box[m-j-1][i]=box[i][j]; 14 for(int i=0;i<m;i++) 15 for(int j=0;j<m;j++) 16 box[i][j]=Box[i][j]; 17 } 18 L gethash(){ 19 L ans=0; 20 for(int i=0;i<m;i++) 21 for(int j=0;j<m;j++) 22 ans=ans<<1|box[i][j]; 23 return ans; 24 } 25 L gethash(int x,int y){ 26 L ans=0; 27 for(int i=0;i<m;i++) 28 for(int j=0;j<m;j++) 29 ans=ans<<1|(ch[i+x][j+y]=='1'); 30 return ans; 31 } 32 33 int wx[]={0,0,1,-1}; 34 int wy[]={1,-1,0,0}; 35 queue<int> qx,qy,qz; 36 void solve(){ 37 memset(dis,60,sizeof(dis)); 38 INF=dis[0][0][0]; 39 dis[0][0][0]=0; 40 qx.push(0); qy.push(0); qz.push(0); 41 while(!qx.empty()){ 42 int x=qx.front(); qx.pop(); 43 int y=qy.front(); qy.pop(); 44 int z=qz.front(),Z; qz.pop(); 45 46 Z=(z+1)&3; 47 if(dis[x][y][z]+1<dis[x][y][Z]&&((b[Z]&a[x][y])==0)){ 48 qx.push(x); qy.push(y); qz.push(Z); 49 dis[x][y][Z]=dis[x][y][z]+1; 50 } 51 52 Z=(z-1)&3; 53 if(dis[x][y][z]+1<dis[x][y][Z]&&((b[Z]&a[x][y])==0)){ 54 qx.push(x); qy.push(y); qz.push(Z); 55 dis[x][y][Z]=dis[x][y][z]+1; 56 } 57 58 for(int i=0;i<4;i++){ 59 int X=x+wx[i],Y=y+wy[i]; 60 if(X<0||Y<0||X>n-m||Y>n-m) continue; 61 if(dis[x][y][z]+1<dis[X][Y][z]&&(b[z]&a[X][Y])==0){ 62 dis[X][Y][z]=dis[x][y][z]+1; 63 qx.push(X); qy.push(Y); qz.push(z); 64 } 65 } 66 } 67 } 68 69 int main(){ 70 scanf("%d%d",&n,&m); 71 for(int i=0;i<m;i++){ 72 scanf("%s",c); 73 for(int j=0;j<m;j++) 74 box[i][j]=c[j]-'0'; 75 } 76 for(int i=0;i<4;i++){ 77 b[i]=gethash(); 78 rotate(); 79 } 80 81 for(int i=0;i<n;i++) 82 scanf("%s",ch[i]); 83 for(int i=0;i<=n-m;i++) 84 for(int j=0;j<=n-m;j++) 85 a[i][j]=gethash(i,j); 86 87 solve(); 88 89 int minn=INF; 90 for(int i=0;i<4;i++) 91 minn=min(minn,dis[n-m][n-m][i]); 92 if(minn==INF) cout<<-1<<endl; 93 else cout<<minn<<endl; 94 }