Solution
70分做法:
- vis[x][y][kx][ky] 表示指定旗子在 (x,y) ,空白格在 (kx,ky) 的状态
- 广搜就是移动空白格
- 当空白格移动到指定旗子的位置时,交换位置
- 队列中每个装态对应的步数是单调不降的,因此第一次走到目标位置就是最小步数
Code
// by spli
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
int n,m,Q;
bool can[35][35];
int ex,ey,sx,sy,tx,ty;
int mx[5]={0,1,0,-1,0};
int my[5]={0,0,1,0,-1};
bool vis[35][35][35][35];
struct node{
int x,y,kx,ky,cnt;
};
queue<node>q;
bool bfs(){
while(!q.empty()) q.pop();
vis[sx][sy][ex][ey]=1;
q.push((node){sx,sy,ex,ey,0});
int x,y,kx,ky;
while(!q.empty()){
node f=q.front();
q.pop();
for(int i=1;i<=4;++i){
x=f.x;y=f.y;
kx=f.kx+mx[i];
ky=f.ky+my[i];
if(kx==x&&ky==y) x=f.kx,y=f.ky;
if(!vis[x][y][kx][ky]&&x<=n&&x>=1&&y<=m&&y>=1&&can[x][y]&&can[kx][ky]){
vis[x][y][kx][ky]=1;
if(x==tx&&y==ty){
printf("%d\n",f.cnt+1);
return 1;
}
q.push((node){x,y,kx,ky,f.cnt+1});
}
}
}
return 0;
}
int main(){
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&can[i][j]);
while(Q--){
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
memset(vis,0,sizeof(vis));
if(sx==tx&&sy==ty){
puts("0");
continue;
}
if(bfs()) continue;
else puts("-1");
}
return 0;
}
满分做法:
- 把广搜的过程分成两个部分:①空白格移动到指定旗子的上下左右+②指定旗子移动到目标位置
- ①过程bfs解决
- ②:当指定旗子要从 (x,y) 移动到 (x+1,y) 时,需要空白格先移动到 (x+1,y) ,又因为此时空白格一定在 (x,y) 上下左右的某个位置,而多次询问中,空白格从某个点上下左右不经过这个点的情况下到达这个点上下左右其它位置的步数是固定的,同样可以bfs预处理
- 因此②可以跑spfa,转移的代价就是预处理的步数
Code
// by spli
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,Q;
bool can[35][35];
int ex,ey,sx,sy,tx,ty;
int mx[5]={0,1,0,-1};
int my[5]={1,0,-1,0};
int mv[35][35][5][5];
int dis[35][35],d[35][35][5];
bool vis[35][35][5];
struct node{
int x,y,z;
};
queue<node>s,q;
bool check(int x,int y){
if(x<1||x>n||y<1||y>m||!can[x][y]) return 0;
return 1;
}
void bfs(int x,int y){
while(!s.empty()) s.pop();
while(!q.empty()) q.pop();
int kx,ky,px,py;
node f;
for(int i=0;i<4;++i){
kx=x+mx[i];
ky=y+my[i];
if(check(kx,ky)) s.push((node){kx,ky,i});
}
while(!s.empty()){
memset(dis,0x3f3f3f3f,sizeof(dis));
f=s.front();
s.pop();
while(!q.empty()) q.pop();
q.push((node){f.x,f.y,f.z});
dis[f.x][f.y]=0;
int z=f.z;
while(!q.empty()){
node f=q.front();
q.pop();
px=f.x;py=f.y;
for(int i=0;i<4;++i){
kx=px+mx[i];
ky=py+my[i];
if(check(kx,ky)&&dis[kx][ky]==inf&&(kx!=x||ky!=y)){
dis[kx][ky]=dis[px][py]+1;
q.push((node){kx,ky,i});
}
}
}
for(int i=0;i<4;++i){
kx=x+mx[i];
ky=y+my[i];
if(check(kx,ky))
mv[x][y][z][i]=dis[kx][ky];
}
}
}
void pre(){
memset(dis,0x3f3f3f3f,sizeof(dis));
dis[ex][ey]=0;
while(!q.empty()) q.pop();
q.push((node){ex,ey,0});
node f;
int kx,ky,px,py;
while(!q.empty()){
f=q.front();
q.pop();
px=f.x;py=f.y;
for(int i=0;i<4;++i){
kx=px+mx[i];
ky=py+my[i];
if(check(kx,ky)&&(kx!=sx||ky!=sy)&&dis[kx][ky]==inf){
dis[kx][ky]=dis[px][py]+1;
q.push((node){kx,ky,0});
}
}
}
}
void spfa(){
if(sx==tx&&sy==ty){
puts("0");
return;
}
node f;
int kx,ky,px,py,z;
memset(d,0x3f3f3f3f,sizeof(d));
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
for(int i=0;i<4;++i){
kx=sx+mx[i];
ky=sy+my[i];
if(check(kx,ky)&&dis[kx][ky]<inf){
q.push((node){sx,sy,i});
d[sx][sy][i]=dis[kx][ky];
vis[sx][sy][i]=1;
}
}
while(!q.empty()){
f=q.front();
q.pop();
px=f.x;py=f.y;z=f.z;
vis[px][py][z]=0;
kx=px+mx[z];
ky=py+my[z];
if(d[kx][ky][(z+2)%4]>d[px][py][z]+1){
d[kx][ky][(z+2)%4]=d[px][py][z]+1;
if(!vis[kx][ky][(z+2)%4]){
vis[kx][ky][(z+2)%4]=1;
q.push((node){kx,ky,(z+2)%4});
}
}
for(int i=0;i<4;++i){
kx=px+mx[i];
ky=py+my[i];
if(check(kx,ky)&&i!=z&&d[px][py][i]>d[px][py][z]+mv[px][py][z][i]){
d[px][py][i]=d[px][py][z]+mv[px][py][z][i];
if(!vis[px][py][i]){
vis[px][py][i]=1;
q.push((node){px,py,i});
}
}
}
}
int ans=inf;
for(int i=0;i<4;++i)
ans=min(ans,d[tx][ty][i]);
if(ans>=inf) puts("-1");
else printf("%d\n",ans);
}
int main(){
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) scanf("%d",&can[i][j]);
memset(mv,0x3f3f3f3f,sizeof(mv));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(can[i][j]) bfs(i,j);
while(Q--){
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
pre();
spfa();
}
return 0;
}