题目来自:ctf2019
题目描述:有最多不超过3个箱子,在不超过1210的地图上有一个人,请把箱子推到对应的位置,求出最短路和路线
数据见代码末的input
状态:人+箱子的状态status 压缩成一个整数 显然在同一个status下,花费不同的距离到达这一个位置,我们要选取其中最短的那条
status的计算方法:整个地图抽象成进制 人的位置和箱子的位置抽象成一个数字 见cal函数 为了避免开过大的数组我们可以将最外围的墙扔掉可以节省不少空间。
#include <bits/stdc++.h>
using namespace std;
#define wall 8
#define human 4
#define box 2
#define destination 1
#define nothing 0
#define pb push_back
#define MAXN 20480000
int G[100][100];
vector<char>ans,tmp;
char s[5] = "awds";
// a w d s
int dx[]={0,-1,0,1};
int dy[]={-1,0,1,0};
int box_num = 0;
int vis[MAXN];
int box_x[4][MAXN];
int box_y[4][MAXN];
int row,col;
struct node
{
int x,y;
node(){}
node(int _x,int _y):x(_x),y(_y){}
}myman;
vector<node> mybox;
vector<node> mydist;
int Min = 1<<20;
bool same(node a,node b){
return a.x==b.x&&a.y==b.y;
}
bool success(int cnt){
for(int i=0;i<box_num;++i){
bool flag = false;
for(int j=0;j<mydist.size();++j){
if(same(node(box_x[i][cnt],box_y[i][cnt]),mydist[j])){
flag=true;
break;
}
}
if(!flag) return false;
}
return true;
}
bool valid(int x,int y){
return x>=0&&x<row&&y>=0&&y<col;
}
int getBoxId(int x,int y,int cnt){
for(int i=0;i<box_num;++i){
if(box_x[i][cnt]==x&&box_y[i][cnt]==y){
return i;
}
}
return -1;
}
int val(node t){
return (t.x)*(col)+t.y; //有效面积整体移到0,0起点
}
int cal(int tempX,int tempY,int cnt){
int ret = val(node(tempX,tempY));
for(int i=0;i<box_num;++i){
ret = ret*(row)*(col)+val(node(box_x[i][cnt],box_y[i][cnt]));
}
return ret;
}
struct p
{
int x,y,len,num;
string path;
p(){}
p(int _x,int _y,int _len,int _num,string _path){
x = _x;
y = _y;
len = _len;
num = _num;
path = _path;
}
};
string path;
void bfs(int x,int y){
queue<p> q;
q.push(p(x,y,0,0,""));
int cnt = 0;
while(!q.empty()){
p tmp = q.front();
q.pop();
if(success(tmp.num)){
if(tmp.len<Min){
Min = tmp.len;
path = tmp.path;
}
continue;
}
for(int i= 0 ; i < 4; ++i){
int fx = tmp.x+dx[i];
int fy = tmp.y+dy[i];
if(!valid(fx,fy)) continue;
if(G[fx][fy]==wall) continue;
int idx = getBoxId(fx,fy,tmp.num);
if(idx>=0){
if(G[fx+dx[i]][fy+dy[i]]==wall||getBoxId(fx+dx[i],fy+dy[i],tmp.num)>=0) continue;
//推箱子
++cnt;//找个新的地方存放箱子的位置
for(int j=0;j<box_num;++j){
box_x[j][cnt] = box_x[j][tmp.num];
box_y[j][cnt] = box_y[j][tmp.num];
}
box_x[idx][cnt] = fx+dx[i];//移动箱子
box_y[idx][cnt] = fy+dy[i];
int status = cal(fx,fy,cnt);//计算状态
if (tmp.len<vis[status]){//状态一致且路径更短
vis[status] = tmp.len;
q.push(p(fx,fy,tmp.len+1,cnt,tmp.path+s[i]));
}
}
else{
int status = cal(fx,fy,tmp.num);
if(tmp.len<vis[status]){
vis[status] = tmp.len;
q.push(p(fx,fy,tmp.len+1,tmp.num,tmp.path+s[i]));
}
}
}
}
}
int main(){
cin>>row>>col;
for(int i=0;i<row;++i){
for(int j=0;j<col;++j){
scanf("%1d",&G[i][j]);
}
}
row -= 2;
col -= 2;
memset(vis,0x3f,sizeof vis);
for(int i=0;i<row;++i){
for(int j=0;j<col;++j){
G[i][j] = G[i+1][j+1];
if(G[i][j]==box){
mybox.pb(node(i,j));
}
else if(G[i][j]==destination){
mydist.pb(node(i,j));
}
else if(G[i][j]==human){
myman.x = i;
myman.y = j;
}
}
}
box_num = mybox.size();
for(int i=0;i<box_num;++i){
box_x[i][0] = mybox[i].x;
box_y[i][0] = mybox[i].y;
}
bfs(myman.x,myman.y);
cout<<path<<endl;
return 0;
}
/*
(8:wall,4:human,2:box,1:destination)
Input 1:
5 10
8888888888
8000000008
8042010008
8000000008
8888888888
Output 1:
dd
Input 2:
12 10
8888888888
8000000008
8008000008
8000000808
8002000008
8000000108
8008808008
8810880008
8000000808
8000804208
8800000088
8888888888
Output 2:
wwddssaasawdwaaasawwwawwwddsasswdddd
Input 3:
5 10
8888888888
8000000008
8042000008
8000000018
8888888888
Output 3:
dddddwds
Input 4:
5 10
8888888888
8000000008
8041200008
8000000008
8888888888
Output 4:
wdddsa
Input 5:
9 10
8888888888
8888880088
8880200088
8800808288
8814110088
8880808008
8880002008
8880088888
8888888888
Output 5:
ddddssaawwwwddssaaaawwddssssasawwwddwwaasasdwwddssddsdsaaaasawwwddwwaasasddawwdddwdssssdsaaaasawwsddwwaawwddddssaaddwwaas
*/