今天是我第一次在这里写解题报告,我还是小菜鸟,请大家多多指教
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1254
我的思路:用广搜找箱子的移动路径,由于考虑到人必须能推的了,所以在每次移动的时候要确定人能够到达推箱子的地方,所以,广搜的同时用深搜确定人的位置。但是在调试过程中发现人的位置用广搜的速度更快,所以最后改成了广搜,提交失败了好几次,总结原因:
一、一开始没有记录一个点走过多少次,导致重复搜索,死循环超时
二、在广搜箱子的同时没有更新人的位置,导致某些数据wa
三、因为考虑到箱子有可能要往回推,所以在去重时犹豫不决,最后用了一个数组,限制每个点最多走3次
四、特殊数据:
400000
020000
000000
000011
000013
来个20组,搜的够呛,所以加了个补丁
另外还有特殊数据
000400
000300
111211
000000
000000
------------------
#include <iostream>
#include <cstdio>
#include <queue>
#include<cstring>
using namespace std;
char map[33][33];
struct node
{
int bx,by,rx,ry,num;//变量含义:箱子x,箱子y,人x,人y,步数
};
queue<node> q;//箱子路径的广搜
queue<node> rq;//人的位置的广搜
node m[5];
int x,y;
bool mark[33][33];
char mrk[33][33];//这个数组是用来记录一个点被走过几次,为了避免搜索时重复走以前的路,不过。。我自己感觉都不明白。。
bool bfs(int rx,int ry,int ex,int ey);
void r_next();
bool dfs(int rx,int ry,int ex,int ey)//人的位置的深搜
{
int i;
if(rx==ex&&ry==ey)
return true;
for(i=1;i<=4;i++)
{
if(map[rx+m[i].bx][ry+m[i].by]=='0'&&map[rx+m[i].bx][ry+m[i].by]!='r')
{
map[rx][ry]='r';
if(dfs(rx+m[i].bx,ry+m[i].by,ex,ey))
{
map[rx][ry]='0';
return true;
}
map[rx][ry]='0';
}
}
return false;
}
void next()//用来确定下一步
{
int i;
node temp=q.front();
for(i=1;i<=4;i++)
{
temp.num=q.front().num+1;
temp.bx=q.front().bx+m[i].bx;
if(temp.bx<1||temp.bx>x)
continue;
temp.by=q.front().by+m[i].by;
if(temp.by<1||temp.by>y)
continue;
if((map[temp.bx][temp.by]=='0'||map[temp.bx][temp.by]=='r')&&bfs(temp.rx,temp.ry,temp.bx-2*m[i].bx,temp.by-2*m[i].by)&&mrk[temp.bx][temp.by]<=2)
{
temp.rx=temp.bx-2*m[i].bx;
temp.ry=temp.by-2*m[i].by;
q.push(temp);
}
}
}
void move()//方便移动用的
{
m[1].bx=-1;m[1].by=0;
m[2].bx=1;m[2].by=0;
m[3].bx=0;m[3].by=-1;
m[4].bx=0;m[4].by=1;
}
int main()
{
//freopen("input.txt","r",stdin);
int n,i,j,endx,endy;
node temp;
bool flag;
move();
cin>>n;
while(n--)
{
flag=false;
memset(map,1,sizeof(map));
scanf("%d %d",&x,&y);
getchar();
for(i=1;i<=x;i++)
{
for(j=1;j<=y;j++)
{
scanf("%c ",&map[i][j]);
if(map[i][j]=='2')
{
temp.bx=i;
temp.by=j;
}
else if(map[i][j]=='3')
{
endx=i;
endy=j;
map[i][j]='0';
}
else if(map[i][j]=='4')
{
temp.rx=i;
temp.ry=j;
map[i][j]='0';
}
}
}
map[temp.bx][temp.by]='0';//这个补丁直接搜人能不能走到箱子的终点,如果人都走不到,箱子也不可能到,算的搜的时候无视箱子
if(!dfs(temp.rx,temp.ry,endx,endy))//一个补丁,用来处理奇怪的数据
{
cout<<"-1"<<endl;
continue;
}
map[temp.bx][temp.by]='2';//补丁搜完了,箱子补上
memset(mrk,0,sizeof(mrk));
temp.num=0;
q.push(temp);
while(!q.empty())//广搜箱子路径
{
map[q.front().bx][q.front().by]='2';//每次要记录人的位置的改变
mrk[q.front().bx][q.front().by]++;
if(q.front().bx==endx&&q.front().by==endy)
{
cout<<q.front().num<<endl;
flag=true;
break;
}
next();
map[q.front().bx][q.front().by]='0';
q.pop();
}
if(!flag)
cout<<"-1"<<endl;
while(!q.empty())
q.pop();
}
return 0;
}
bool bfs(int rx,int ry,int ex,int ey)//人的广搜函数,4个参数别是起始位置x,起始位置y,终点位置x,终点位置y
{
node temp;
memset(mark,true,sizeof(mark));
temp.rx=rx;
temp.ry=ry;
rq.push(temp);
while(!rq.empty())
{
if(rq.front().rx==ex&&rq.front().ry==ey)
{
while(!rq.empty())
rq.pop();
return true;
}
r_next();
rq.pop();
}
while(!rq.empty())
rq.pop();
return false;
}
void r_next()//人的下一步计算函数
{
node temp;
int i;
for(i=1;i<=4;i++)
{
temp.rx=rq.front().rx+m[i].bx;
if(temp.rx<1||temp.rx>x)
continue;
temp.ry=rq.front().ry+m[i].by;
if(temp.ry<1||temp.ry>y)
continue;
if(map[temp.rx][temp.ry]=='0'&&mark[temp.rx][temp.ry]!=false)
{
mark[temp.rx][temp.ry]=false;
rq.push(temp);
}
}
}