【GDOI2015】 推箱子 状态压缩+bfs

时间:2023-03-10 03:55:04
【GDOI2015】 推箱子 状态压缩+bfs

【GDOI2015】 推箱子 状态压缩+bfs

【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)的,似乎问题不大。

 #include<bits/stdc++.h>
#define M 2005
#define L unsigned long long
using namespace std;
int INF;
char c[]={},ch[M][M]={};
int n,m,box[][]={},Box[][]={},dis[M][M][]={};
L b[]={},a[M][M]={}; void rotate(){
for(int i=;i<m;i++)
for(int j=;j<m;j++)
Box[m-j-][i]=box[i][j];
for(int i=;i<m;i++)
for(int j=;j<m;j++)
box[i][j]=Box[i][j];
}
L gethash(){
L ans=;
for(int i=;i<m;i++)
for(int j=;j<m;j++)
ans=ans<<|box[i][j];
return ans;
}
L gethash(int x,int y){
L ans=;
for(int i=;i<m;i++)
for(int j=;j<m;j++)
ans=ans<<|(ch[i+x][j+y]=='');
return ans;
} int wx[]={,,,-};
int wy[]={,-,,};
queue<int> qx,qy,qz;
void solve(){
memset(dis,,sizeof(dis));
INF=dis[][][];
dis[][][]=;
qx.push(); qy.push(); qz.push();
while(!qx.empty()){
int x=qx.front(); qx.pop();
int y=qy.front(); qy.pop();
int z=qz.front(),Z; qz.pop(); Z=(z+)&;
if(dis[x][y][z]+<dis[x][y][Z]&&((b[Z]&a[x][y])==)){
qx.push(x); qy.push(y); qz.push(Z);
dis[x][y][Z]=dis[x][y][z]+;
} Z=(z-)&;
if(dis[x][y][z]+<dis[x][y][Z]&&((b[Z]&a[x][y])==)){
qx.push(x); qy.push(y); qz.push(Z);
dis[x][y][Z]=dis[x][y][z]+;
} for(int i=;i<;i++){
int X=x+wx[i],Y=y+wy[i];
if(X<||Y<||X>n-m||Y>n-m) continue;
if(dis[x][y][z]+<dis[X][Y][z]&&(b[z]&a[X][Y])==){
dis[X][Y][z]=dis[x][y][z]+;
qx.push(X); qy.push(Y); qz.push(z);
}
}
}
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<m;i++){
scanf("%s",c);
for(int j=;j<m;j++)
box[i][j]=c[j]-'';
}
for(int i=;i<;i++){
b[i]=gethash();
rotate();
} for(int i=;i<n;i++)
scanf("%s",ch[i]);
for(int i=;i<=n-m;i++)
for(int j=;j<=n-m;j++)
a[i][j]=gethash(i,j); solve(); int minn=INF;
for(int i=;i<;i++)
minn=min(minn,dis[n-m][n-m][i]);
if(minn==INF) cout<<-<<endl;
else cout<<minn<<endl;
}