题目:UVA 11624 Fire!(用的洛谷)
阿伟今天在刷kuangbin大佬的题时,有一道需要用两次BFS的题,由于是海外OJ,因此也没提交上去,不过思想掌握了是最重要的。
题目大意: Joe被困在迷宫,迷宫里有火源,Joe和火源每分钟都可以移动一个单位,并且火源在这一分钟内可以向上下左右四个方向传播(如果没有墙的话),求出Joe能否逃出迷宫(走到边缘就算逃出成功),如果可以逃出,输出最短时间,如果不可以,输出“IMPOSSIBLE”。
(注意:不只有一个火源!!!)
题解: 此题由于Joe的路径并不会改变火的传播,而火的传播会改变Joe的路径,因此选择用两次BFS来完成。一次BFS是将火传播到每个地方的时间用BFS写出来,然后再次用BFS将Joe的路线找出。在开始的时候time数组初始化为无穷大,当其中元素为无穷大时,说明这个地方火到达不到。在存地图的时候,由于可能有多个火源,于是要每次读取的时候判断一下是不是“F”,如果是的话,入队。在Joe的BFS中,check时,要比较Joe到达所在的位置与火传播到这个位置所需要的时间,如果Joe比火先到达该位置,说明该位置是可行的。
上代码(不确定是否正确,交到UVA上老说编译错误,嘤嘤嘤~)
#include
#include
#include
using namespace std;
char maps[1001][1001];
int vis[1001][1001];
int time[1001][1001];
int dir[4][2]=
{
{1,0},
{-1,0},
{0,1},
{0,-1},
};
int sx,sy,r,c;
struct node
{
int x;
int y;
int time;
};
queue<node>q;
bool check_fire(int x,int y)
{
if(x<0||y<0||x>=c||y>=r)
return false;
else
if(maps[x][y]=='#'||vis[x][y])
return false;
return true;
}
bool check_Joe(int x,int y,int times)
{
if(x<0||y<0||x>=r||y>=c)
return false;
else
if(maps[x][y]=='#'||vis[x][y]||times>=time[x][y])
return false;
return true;
}
void bfs_fire()
{
node next;
while(!q.empty())
{
node tmp=q.front();
q.pop();
for(int i=0;i<4;i++)
{
next=tmp;
next.x+=dir[i][0];
next.y+=dir[i][1];
if(check_fire(next.x,next.y))
{
next.time++;
vis[next.x][next.y]=1;
time[next.x][next.y]=next.time;
q.push(next);
}
}
}
}
int bfs_Joe()
{
node start,next;
start.x=sx;
start.y=sy;
start.time=0;
q.push(start);
vis[sx][sy]=1;
while(!q.empty())
{
node tmp=q.front();
q.pop();
if(tmp.x==0||tmp.y==0||tmp.x==r-1||tmp.y==c-1)
return tmp.time+1;
for(int i=0;i<4;i++)
{
next=tmp;
next.x+=dir[i][0];
next.y+=dir[i][1];
next.time++;
if(check_Joe(next.x,next.y,next.time))
{
vis[next.x][next.y]=1;
q.push(next);
}
}
}
return -1;
}
int main()
{
int t;
cin>>t;
while(t--)
{
while(!q.empty())
q.pop();
cin>>r>>c;
memset(maps,0,sizeof(maps));
memset(vis,0,sizeof(vis));
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
cin>>maps[i][j];
if(maps[i][j]=='F')
{
node tmp;
tmp.x=i;
tmp.y=j;
tmp.time=0;
time[i][j]=0;
vis[i][j]=1;
q.push(tmp);
}
else
if(maps[i][j]=='J')
{
sx=i;
sy=j;
}
}
}
for(int i=0;i<1001;i++)
{
for(int j=0;j<1001;j++)
time[i][j]=1e9+7;
}
bfs_fire();
memset(vis,0,sizeof(vis));
int ans=bfs_Joe();
if(ans==-1)
cout<<"IMPOSSIBLE"<<endl;
else
cout<<ans<<endl;
}
}
题目:hdoj 2612 Find a way
这题也是阿伟自己出的呦~
题目大意: 有两个人Y和M要去KFC见面,但城市里有很多KFC,他们想找一个用时最短的KFC,注意:用时是两个人的总时间,并不是两个人用时最长的那个。
题解: 看到这个题,我首先想到的是对每个KFC用BFS搜,但是看了大佬的题解之后,说那个方法会超时,因为不知道有多少KFC,有可能会有很多,然而这样就会超时。于是我就想对Y和M两个人用BFS,这样找出这两个人到达每个KFC所用的时间,然后找出总时间最少的那个就可以了。在这里我用了三维数组,因为对两个人用BFS是完全相同的,用三维数组避免了写两次BFS。
AC代码:
#include
#include
#include
using namespace std;
char maps[201][201];
int kfc[201][201];//记录两人到达某个KFC的总时间
int vis[2][201][201];//用三维数组避免写两次bfs
int n,m,yx,yy,mx,my;
int mins=1e9+7;//记录两人到达某KFC的最短时间
struct node
{
int x;
int y;
int time;
};
int dir[4][2]=
{
{1,0},
{-1,0},
{0,1},
{0,-1},
};
bool check(int x,int y,int k)
{
if(x<0||y<0||x>=n||y>=m)
return false;
else
if(maps[x][y]=='#'||vis[k][x][y])
return false;
return true;
}
void bfs()
{
queue<node>q;
node start,next;
for(int k=0;k<2;k++)
{
if(k==0)
{
start.x=yx;
start.y=yy;
}
else
{
start.x=mx;
start.y=my;
}
start.time=0;
q.push(start);
vis[k][start.x][start.y]=1;
while(!q.empty())
{
node tmp=q.front();
q.pop();
for(int i=0;i<4;i++)
{
next=tmp;
next.x+=dir[i][0];
next.y+=dir[i][1];
if(check(next.x,next.y,k))
{
next.time++;
if(maps[next.x][next.y]=='@')
{
kfc[next.x][next.y]+=next.time;
if(kfc[next.x][next.y]<mins&&k==1)//在这里判断大小的话,只能是在第二个人之后,因此要加上k==1这个判别条件
mins=kfc[next.x][next.y];//在这里判断就不用再在下面排序找最小值了
}
vis[k][next.x][next.y]=1;
q.push(next);
}
}
}
}
}
int main()
{
while(cin>>n>>m)
{
mins=1e9+7;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>maps[i][j];
if(maps[i][j]=='Y')
{
yx=i;
yy=j;
}
else
if(maps[i][j]=='M')
{
mx=i;
my=j;
}
}
}
memset(kfc,0,sizeof(kfc));
memset(vis,0,sizeof(vis));
bfs();
cout<<mins*11<<endl;
}
}