4.2.1 HDU1242 Rescue
一道简单的BFS,有一点DP的感觉在里面,因为打守卫会耽误时间,所以在搜索一个格子时不能单纯的看它是否搜索过,如果从这条路能更快的走到这个点就要对这个点进行跟新.
#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
struct pos{
int x,y,step;
pos(){}
pos(int a,int b){x=a,y=b;}
}p;
char maze[205][205];
int step[205][205];
int ax,ay,rx,ry,n,m;
int delta[2][4]={{1,-1,0,0},{0,0,1,-1}};
int bfs(){
queue<pos> q;
while(!q.empty())q.pop();
memset(step,-1,sizeof step);
q.push(pos(rx,ry));
step[rx][ry]=0;
while(!q.empty()){
pos tp=q.front();q.pop();
for(int i=0;i<4;i++){
int nx=tp.x+delta[0][i],ny=tp.y+delta[1][i];
if(nx==ax&&ny==ay)return step[tp.x][tp.y]+1;
if(maze[nx][ny]!='#'){
if(step[nx][ny]==-1||step[tp.x][tp.y]+(maze[nx][ny]=='.'?1:2)<step[nx][ny]){
q.push(pos(nx,ny));
step[nx][ny]=step[tp.x][tp.y]+(maze[nx][ny]=='.'?1:2);
}
}
}
}
return -1;
}
int main(){
while(~scanf("%d%d",&n,&m)!=EOF){
//初始化迷宫以及边界
for(int i=1;i<=n;i++){
scanf("%s",maze[i]+1);
for(int j=1;j<=m;j++){
if(maze[i][j]=='a')ax=i,ay=j;
else if(maze[i][j]=='r')rx=i,ry=j;
}
}
for(int i=0;i<=m+1;i++)maze[0][i]=maze[n+1][i]='#';
for(int i=0;i<=n+1;i++)maze[i][0]=maze[i][m+1]='#';
int r=bfs();
if(r==-1)printf("Poor ANGEL has to stay in the prison all his life.\n");
else printf("%d\n",r);
}
return 0;
}
4.2.3 HDU1372 Knight Moves
两道没有什么技巧的BFS..
4.2.4 HDU1728 逃离迷宫
每次跟新整行,直到不能跟新,注意:跟新的点未访问过,或者到该点的转向次数小于之前的决策
#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
int cas,n,m,c1,c2,r1,r2,k;
char maze[205][205];
int dir[205][205];
struct pos{
int r,c;
pos(int x,int y){r=x,c=y;}
};
int dr[]={1,-1,0,0};
int dc[]={0,0,1,-1};
bool bfs(){
if(r2==r1&&c2==c1)return true;
queue<pos> q;
memset(dir,-1,sizeof dir);
q.push(pos(r1,c1));
dir[r1][c1]=0;
while(!q.empty()){
pos tp=q.front();q.pop();
for(int i=0;i<4;i++){
int nr=tp.r+dr[i],nc=tp.c+dc[i];
// 每次跟新整行,直到不能跟新,注意(跟新的点未访问过,或者到该点的次数小于之前的决策)
while(nr>=1&&nc>=1&&nr<=m&&nc<=n&&maze[nr][nc]!='*'&&(dir[nr][nc]==-1||dir[tp.r][tp.c]+1<=dir[nr][nc])){
dir[nr][nc]=dir[tp.r][tp.c]+1;
q.push(pos(nr,nc));
if(dir[r2][c2]!=-1&&dir[r2][c2]<=k+1)return true;
nr+=dr[i];
nc+=dc[i];
}
}
}
if(dir[r2][c2]<=k+1&&dir[r2][c2]!=-1)return true;
return false;
}
int main(){
scanf("%d",&cas);
while(cas--){
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)scanf("%s",maze[i]+1);
scanf("%d%d%d%d%d",&k,&c1,&r1,&c2,&r2);
printf(bfs()?"yes\n":"no\n");
}
return 0;
}
4.2.5 HDU1252 Hike on a Graph
题意真的是不好理解,就是说A可以到x点仅当A-x与B-C的颜色一样
理解的题意就是一道很简单的BFS了..用三维的VIS数组标记三个球的位置
#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
struct pos{int x,y,z;pos(int a,int b,int c){x=a,y=b,z=c;}};
int n,p1,p2,p3;
char map[60][60];
int vis[60][60][60];
/*
BFS 三个点,x->i仅当color[x][i]=color[y][z]
*/
int bfs(){
memset(vis,0,sizeof vis);
queue<pos> q;
q.push(pos(p1,p2,p3));
vis[p1][p2][p3]=1;
while(!q.empty()){
pos p=q.front();q.pop();
if(p.x==p.y&&p.y==p.z)return vis[p.x][p.y][p.z]-1;
for(int i=1;i<=n;i++){
if(map[p.x][p.y]==map[p.z][i]&&!vis[p.x][p.y][i]){
vis[p.x][p.y][i]=vis[p.x][p.y][p.z]+1;
q.push(pos(p.x,p.y,i));
}
if(map[p.z][p.x]==map[p.y][i]&&!vis[p.x][i][p.z]){
vis[p.x][i][p.z]=vis[p.x][p.y][p.z]+1;
q.push(pos(p.x,i,p.z));
}
if(map[p.y][p.z]==map[p.x][i]&&!vis[i][p.y][p.z]){
vis[i][p.y][p.z]=vis[p.x][p.y][p.z]+1;
q.push(pos(i,p.y,p.z));
}
}
}
return -1;
}
int main(){
while(scanf("%d",&n),n){
scanf("%d%d%d",&p1,&p2,&p3);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf(" %c",&map[i][j]);
int r=bfs();
if(r==-1)printf("impossible\n");
else printf("%d\n",r);
}
return 0;
}
4.3.6 HDU2612 Find A Way
找一个KFC使两人到KFC的距离和最小,一开始从KFC考虑..TLE了
换个思路,从人来考虑,求出这两个人到地图上所有位置的最短距离,然后枚举KFC位置两人路程和就可以了..
4.3.7 HDU2653 Waiting ten thousand years for Love
这题的题意弄了很久才弄明白,对于'@'是必须要飞上去,然后在飞走的,一个'@'消耗的能量实际是两点,而对于'.'就没有飞与走的规定了,可以飞上走下,走上走下等等..
代码敲的很久,可能是因为思路不清晰的缘故吧..其实每个点都去考虑两种情况..优先去考虑飞行,因为这样能更快的到达魔王那里,只要能量大于0,就有可能飞行,而对于走,只要即将要走的以及出来的位置不是'@',就可以步行..另外因为到达一个点可能会有不同的能量值,所以要用一个三维的数组去标记状态
#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
struct pos{
int r,c,p,s;
pos(int w,int x,int y,int z){r=w,c=x,p=y,s=z;}
};
int n,m,p,t,sr,sc,er,ec;
bool vis[82][82][82];
int dr[]={0,0,1,-1},dc[]={1,-1,0,0};
char maze[82][82];
int bfs(){
queue<pos> q;
memset(vis,0,sizeof vis);
q.push(pos(sr,sc,p,0));
vis[sr][sc][p]=true;
while(!q.empty()){
pos tp=q.front();q.pop();
//reach in time
if(tp.r==er&&tp.c==ec&&tp.s<=t)return tp.s
for(int i=0;i<4;i++){
int nr=tp.r+dr[i],nc=tp.c+dc[i];
if(nr<1||nr>n||nc<1||nc>m||maze[nr][nc]=='#')continue;
//FLY
if(tp.p>0&&!vis[nr][nc][tp.p-1]){
q.push(pos(nr,nc,tp.p-1,tp.s+1));
vis[nr][nc][tp.p-1]=true;
}
//WALK
if(maze[tp.r][tp.c]=='@'||maze[nr][nc]=='@')continue;//CAN`T WALK
if(!vis[nr][nc][tp.p]){
q.push(pos(nr,nc,tp.p,tp.s+2));
vis[nr][nc][tp.p]=true;
}
}
}
return -1;
}
int main(){
int cas=1;
while(scanf("%d%d%d%d",&n,&m,&t,&p)!=EOF){
for(int i=1;i<=n;i++){
scanf("%s",maze[i]+1);
for(int j=1;j<=m;j++){
if(maze[i][j]=='Y')sr=i,sc=j;
if(maze[i][j]=='L')er=i,ec=j;
}
}
int r=bfs();
printf("Case %d:\n",cas++);
if(r==-1)printf("Poor Yifenfei, he has to wait another ten thousand years.\n");
else printf("Yes, Yifenfei will kill Lemon at %d sec.\n",r);
}
return 0;
}
4.2.8 HDU2531 Catch Him
比较水,以防守队员的左上角坐标为基准坐标并且用这个点来访问标记就可以了,每次判断的时候要对防守队员身体的所有部分进行判定的..一开始一直WA..找了半天错,后来发现是为了方便在一次循环中判定是否碰到四分卫或者捉到防守队员了..2了一下,最后一次碰到四分卫也可能也碰到防守队员了..这应该算没抓到的情况..
#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
struct pos{int r,c;pos(int a,int b){r=a,c=b;}};
char maze[120][120];
int n,m,str,stc,fs,fsd[25][2],step[120][120];
int dr[]={1,-1,0,0},dc[]={0,0,1,-1};
int moveres(int nr,int nc){
if(step[nr][nc]!=-1)return 0;//已移动过
for(int i=0;i<fs;i++){
int r=nr-str+fsd[i][0],c=nc-stc+fsd[i][1];
if(r<1||c<1||r>n||c>m)return 0;//超出边界
if(maze[r][c]=='O')return 0;//防守队员
}
//注意要分开判断,先判断这步符不符合要求在判断是否抓到
for(int i=0;i<fs;i++){
int r=nr-str+fsd[i][0],c=nc-stc+fsd[i][1];
if(maze[r][c]=='Q')return 2;//抓到四分卫
}
return 1;//可以移动
}
int bfs(int sr,int sc){
if(sr==0)return -1;
memset(step,-1,sizeof step);
queue<pos> q;
q.push(pos(sr,sc));
step[sr][sc]=0;
while(!q.empty()){
pos tp=q.front();q.pop();
for(int i=0;i<4;i++){
int nr=tp.r+dr[i],nc=tp.c+dc[i];
int r=moveres(nr,nc);//移动的结果,0不可,1可移,2抓到四分卫
if(r==2)return step[tp.r][tp.c]+1;
if(r==0)continue;
step[nr][nc]=step[tp.r][tp.c]+1;
q.push(pos(nr,nc));
}
}
return -1;
}
int main(){
while(scanf("%d%d",&n,&m),n||m){
str=0,stc=0;//防守队员左上角的坐标
fs=0;//防守队员体积
for(int i=1;i<=n;i++){
scanf("%s",maze[i]+1);
for(int j=1;j<=m;j++){
if(maze[i][j]=='D'){
fsd[fs][0]=i,fsd[fs][1]=j,fs++;
if(str==0)str=i,stc=j;
}
}
}
int r=bfs(str,stc);
if(r==-1)printf("Impossible\n");
else printf("%d\n",r);
}
return 0;
}
本文精选多道BFS算法题目,深入浅出地讲解BFS的应用场景与实现细节,包括迷宫逃脱、寻找最优路径等问题。
1015

被折叠的 条评论
为什么被折叠?



