题解 P3855 【[TJOI2008]Binary Land】
算法分析:BFS
显然是爆搜题(虽然不知道为什么有 dp 标签)(雾)。
首先是状态,我们应该记录两只企鹅的位置和走到当前状态所需的步数,如果走过这个状态,那么不再重复走。
struct P {
int x,y,a,b,step;//位置,步数
}g,m;
其次是对状态的可行性检查。我在检查状态完毕后直接对状态进行了修改,这样可以使 BFS 主体简短一点。
inline bool check(int &x,int &y,int &a,int &b,P t) {
//t 是没移动之前的状态
if(pc[x][y]=='X'||pc[a][b]=='X'){//蜘蛛网,失败
vis[x][y][a][b]=1;
return false;
}
if(pc[x][y]=='#')vis[x][y][a][b]=1,x=t.x,y=t.y;//其中一只撞到了,就往回退
if(pc[a][b]=='#')vis[x][y][a][b]=1,a=t.a,b=t.b;//另一只...
if(vis[x][y][a][b])return false;//如果两只都撞到了,那么vis一定被标记过,退出
vis[x][y][a][b]=1;//没走过的状态,标记一下
return true;
}
最后是一些小技巧。比如说,预处理两只企鹅的移动,记录在数组 \(g_1\) 和 \(g_2\) 里。在预处理时,直接将两只企鹅的移动方式对应起来,这样在移动时比较方便(详见代码)。
code:
#include<bits/stdc++.h>
#define reg register
using namespace std;
const int N=50;
bool vis[N][N][N][N];
char pc[N][N];
int g1[10][2] {1,0,0,-1,0,1,-1,0};
int g2[10][2] {1,0,0,1,0,-1,-1,0};
//g1 和 g2 在储存时直接对应起来
struct P {
int x,y,a,b,step;//位置,步数
}g,m;
inline bool check(int &x,int &y,int &a,int &b,P t) {
//t 是没移动之前的状态
if(pc[x][y]=='X'||pc[a][b]=='X'){//蜘蛛网,失败
vis[x][y][a][b]=1;
return false;
}
if(pc[x][y]=='#')vis[x][y][a][b]=1,x=t.x,y=t.y;//其中一只撞到了,就往回退
if(pc[a][b]=='#')vis[x][y][a][b]=1,a=t.a,b=t.b;//另一只...
if(vis[x][y][a][b])return false;//如果两只都撞到了,那么vis一定被标记过,退出
vis[x][y][a][b]=1;//没走过的状态,标记一下
return true;
}
inline void bfs(int xx,int yy,int aa,int bb) {
queue<P> q;
q.push({xx,yy,aa,bb,0});
vis[xx][yy][aa][bb]=1;
while(!q.empty()) {
reg P t=q.front();
q.pop();
for(reg int i=0; i<4; i++) {
reg int x=t.x+g1[i][0],y=t.y+g1[i][1];//移动
reg int a=t.a+g2[i][0],b=t.b+g2[i][1];
if(check(x,y,a,b,t)) {
if(pc[x][y]=='T'&&pc[a][b]=='T') {//走到终点了
printf("%d",t.step+1);
exit(0);
}
q.push({x,y,a,b,t.step+1});
}
}
}
}
int main() {
cin.tie(0);
reg int r,c;
cin>>r>>c;
for(reg int i=1;i<=r;i++){
for(reg int j=1;j<=c;j++){
cin>>pc[i][j];
if(pc[i][j]=='G')g={i,j};//Gurin位置
if(pc[i][j]=='M')m={i,j};//Malon位置
}
}
bfs(g.x,g.y,m.x,m.y);
cout<<"no";
return 0;
}
(目前最优解)
欢迎交流讨论,请点个赞哦~
本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/14920567.html