BFS简单专题总结 BFS的入门之路

先给出BFS的思路吧,大概都是这样做的

struct node
{
	int x, y, step;
};//根据需要定义结构体
int vis[MAX][MAX]={0};//二维三维之类的看题目给的条件
queue q;
q.push(start);//把起点压入队列
node pre,nex;
vis[start.x][start.y]=1;//一般是设置为1,如果有其他需要可以更改
while(!q.empty()){
    pre = q.front();
    if(xxx) break; //xxx是终点的判断
    q.pop();
    for(int i=0;i<4;i++){//i不一定是小于4,看题目来定
        if(xxxx){//如果满足怎样的条件将这种情况压入队列
            q.push(xx);
            vis[xx.x][xx.y]=1;//别忘了标记来过
        }
    }
}
if(!q.empty()){
    //就是找到了终点
}
else{
    //没有找到终点
}

入门的是遇到的一道马跳题,比较简单

Knight Moves

A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.

Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.

Input Specification

The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.

Output Specification

For each test case, print one line saying "To get from xx to yy takes n knight moves.".

Sample Input

e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6

Sample Output

To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.

题意:马步踏棋,日字走法,问你几步能到达终点。所以方向有八个!!!

#include 
#include 
using namespace std;
struct node
{char x;
int y,step;};
int main(){
    char x1,x2;
    int y1,y2;
    queue q;
    node start,temp;
    while(~scanf("%c%d %c%d",&x1,&y1,&x2,&y2)){
            getchar();
        int vis[150][9]={0};
        for(int i=0;i<150;i++)
            for(int j=0;j<9;j++)
                vis[i][j]=0;
        while(!q.empty())//清空
                q.pop();
        start.x=x1;start.y=y1;start.step=0;
        q.push(start);
        vis[start.x][start.y]=1;
        while(!q.empty()){
            start = q.front();
            if(start.x==x2&&start.y==y2)break;
            q.pop();
            //2,1
            temp.x=start.x+2;temp.y=start.y+1;
            if(temp.x<='h'&&temp.y<=8&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //2,-1
            temp.x=start.x+2;temp.y=start.y-1;
            if(temp.x<='h'&&temp.y>0&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //-2,1
            temp.x=start.x-2;temp.y=start.y+1;
            if(temp.x>='a'&&temp.y<=8&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //-2,-1
            temp.x=start.x-2;temp.y=start.y-1;
            if(temp.x>='a'&&temp.y>=1&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //1,2
            temp.x=start.x+1;temp.y=start.y+2;
            if(temp.x<='h'&&temp.y<=8&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //1,-2
            temp.x=start.x+1;temp.y=start.y-2;
            if(temp.x<='h'&&temp.y>0&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //-1,2
            temp.x=start.x-1;temp.y=start.y+2;
            if(temp.x>='a'&&temp.y<=8&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
            //-1,-2
            temp.x=start.x-1;temp.y=start.y-2;
            if(temp.x>='a'&&temp.y>=1&&vis[temp.x][temp.y]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.x][temp.y]=1;
            }
        }
        printf("To get from %c%d to %c%d takes %d knight moves.\n",x1,y1,x2,y2,q.front().step);
    }
}

当时没有用一个数组把8种情况存下来,所以造成代码量比较多。。。

然后就是另一种BFS了(基础类型的变形)

A strange lift

Problem Description
There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button "UP" , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button "DOWN" , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can't go up high than N,and can't go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button "UP", and you'll go up to the 4 th floor,and if you press the button "DOWN", the lift can't do it, because it can't go down to the -2 th floor,as you know ,the -2 th floor isn't exist.
Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button "UP" or "DOWN"?
 

Input
The input consists of several test cases.,Each test case contains two lines.
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,....kn.
A single 0 indicate the end of the input.
 

Output
For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can't reach floor B,printf "-1".
 

Sample Input
5 1 53 3 1 2 50
 

Sample Output
3

题意:有一个特别的电梯,第i层有一个对应的数字ki, 对于第i层按上升键up可升上到i+k[i]层,按下降键down到达i-k[i]层,到达的楼层最高不能超过n层,最低不能小于1层。给你一个起点A和终点B,问最少要按几次上升键或者下降键到达目的地。

思路:多用一个数组记录每一层楼能咋走,其实就是用这个把For循环的那部分代替了,就是这部分创新,其实自己思考下也能做出来的

#include
using namespace std;
struct node
{int lou,step;};
int main(){
    int a,b,c;
    queue q;
    node start,temp;
    while(scanf("%d",&a)&&a!=0){
        scanf("%d %d",&b,&c);
        int floor[200]={0},vis[200]={0};
        for(int i=1;i <= a;i++){
            scanf("%d",&floor[i]);
            vis[i]=0;
        }
        while(!q.empty())//清空
                q.pop();
        start.lou=b;start.step=0;
        q.push(start);
        vis[start.lou]=1;
        while(!q.empty()){
            start = q.front();
            if(start.lou==c)break;
            q.pop();
            temp.lou=start.lou+floor[start.lou];
            if(temp.lou<=a&&vis[temp.lou]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.lou]=1;
            }
            temp.lou=start.lou-floor[start.lou];
            if(temp.lou>0&&vis[temp.lou]!=1){
                temp.step=start.step+1;
                q.push(temp);
                vis[temp.lou]=1;
            }
        }
        if(q.empty()) printf("-1\n");
        else printf("%d\n",q.front().step);
    }
}

又是一种新类型!!!划重点!!

逃离迷宫

Problem Description
  给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?
 

Input
  第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,
  第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,y1, y2对应行。
 

Output
  每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。
 

Sample Input
25 5...***.**...........*....1 1 1 1 35 5...***.**...........*....2 1 1 1 3
 

Sample Output
no yes

题解:这是一种新的类型,如果没有用优先队列的话要给vis赋予其新的意义,我是让

他记录走过的步数,等贴出代码之后再进行解释为什么要这么做

#include
using namespace std;
struct node
{int x,y,wan,fangxiang;};
int vis[101][101];
int main(){
    int x1,x2,y1,y2,k;
    int a,b,c;
    queue q;
    node start,temp;
    scanf("%d",&a);
    while(a--){
        char map[101][101]={'\0'};
        scanf("%d %d",&b,&c);
        for(int i=0;i=temp.wan)&&temp.x=temp.wan)&&temp.y=0&&(vis[temp.x][temp.y]==0||vis[temp.x][temp.y]>=temp.wan)&&map[temp.x][temp.y]=='.'&&start.wan<=k+1){
                //printf("down\n");
                if(start.fangxiang==3){
                    temp.fangxiang=3;
                    temp.wan=start.wan;
                }
                else{
                    temp.fangxiang=3;
                    temp.wan=start.wan+1;
                }
                vis[temp.x][temp.y]=temp.wan;
                //printf("turn:%d\n",temp.wan);
                q.push(temp);
            }

            //向左
            temp.x=start.x;temp.y=start.y-1;
            if(start.fangxiang==4)temp.wan=start.wan;
            else temp.wan=start.wan+1;
            if(temp.y>=0&&(vis[temp.x][temp.y]==0||vis[temp.x][temp.y]>=temp.wan)&&map[temp.x][temp.y]=='.'&&start.wan<=k+1){
                //printf("left\n");
                if(start.fangxiang==4){
                    temp.fangxiang=4;
                    temp.wan=start.wan;
                }
                else{
                    temp.fangxiang=4;
                    temp.wan=start.wan+1;
                }
                vis[temp.x][temp.y]=temp.wan;
                q.push(temp);
            }
        }
        if(q.empty()){
            printf("no\n");
        }
        else
            printf("yes\n");
    }
}

现在来解释为啥需要这么做,这其实因为先左再下与先下再左步数虽然一致,但是从(0,0)到(1,1)之后,(1,1)的方向可不一样,下一次向下或者向左很影响转弯数的增减,所以要标记

又是一种新类型的变形!!!划重点!!

Ignatius and the Princess I

Problem Description
The Princess has been abducted by the BEelzebub feng5166, our hero Ignatius has to rescue our pretty Princess. Now he gets into feng5166's castle. The castle is a large labyrinth. To make the problem simply, we assume the labyrinth is a N*M two-dimensional array which left-top corner is (0,0) and right-bottom corner is (N-1,M-1). Ignatius enters at (0,0), and the door to feng5166's room is at (N-1,M-1), that is our target. There are some monsters in the castle, if Ignatius meet them, he has to kill them. Here is some rules:

1.Ignatius can only move in four directions(up, down, left, right), one step per second. A step is defined as follow: if current position is (x,y), after a step, Ignatius can only stand on (x-1,y), (x+1,y), (x,y-1) or (x,y+1).
2.The array is marked with some characters and numbers. We define them like this:
. : The place where Ignatius can walk on.
X : The place is a trap, Ignatius should not walk on it.
n : Here is a monster with n HP(1<=n<=9), if Ignatius walk on it, it takes him n seconds to kill the monster.

Your task is to give out the path which costs minimum seconds for Ignatius to reach target position. You may assume that the start position and the target position will never be a trap, and there will never be a monster at the start position.
 

Input
The input contains several test cases. Each test case starts with a line contains two numbers N and M(2<=N<=100,2<=M<=100) which indicate the size of the labyrinth. Then a N*M two-dimensional array follows, which describe the whole labyrinth. The input is terminated by the end of file. More details in the Sample Input.
 

Output
For each test case, you should output "God please help our poor hero." if Ignatius can't reach the target position, or you should output "It takes n seconds to reach the target position, let me show you the way."(n is the minimum seconds), and tell our hero the whole path. Output a line contains "FINISH" after each test case. If there are more than one path, any one is OK in this problem. More details in the Sample Output.
 

Sample Input
5 6.XX.1...X.2.2...X....XX.XXXXX.5 6.XX.1...X.2.2...X....XX.XXXXX15 6.XX.....XX1.2...X....XX.XXXXX.
 

Sample Output
It takes 13 seconds to reach the target position, let me show you the way.1s:(0,0)->(1,0)2s:(1,0)->(1,1)3s:(1,1)->(2,1)4s:(2,1)->(2,2)5s:(2,2)->(2,3)6s:(2,3)->(1,3)7s:(1,3)->(1,4)8s:FIGHT AT (1,4)9s:FIGHT AT (1,4)10s:(1,4)->(1,5)11s:(1,5)->(2,5)12s:(2,5)->(3,5)13s:(3,5)->(4,5)FINISHIt takes 14 seconds to reach the target position, let me show you the way.1s:(0,0)->(1,0)2s:(1,0)->(1,1)3s:(1,1)->(2,1)4s:(2,1)->(2,2)5s:(2,2)->(2,3)6s:(2,3)->(1,3)7s:(1,3)->(1,4)8s:FIGHT AT (1,4)9s:FIGHT AT (1,4)10s:(1,4)->(1,5)11s:(1,5)->(2,5)12s:(2,5)->(3,5)13s:(3,5)->(4,5)14s:FIGHT AT (4,5)FINISHGod please help our poor hero.FINISH

题解:给你一个图,图上的标志如题所述,碰到怪兽就一定要把它杀死,求花时间最少的最短路径。

这个题贼好,真的贼好,有很多新颖的点,这个也要赋予VIS数组实际意义,详细的贴完代码说

#include
using namespace std;
struct node
{int x,y,time;};
int vis[120][120];
int a,b;
int turn[4][2]={0,1,1,0,0,-1,-1,0};
node start,temp;
bool check(int x,int y,int z){
    if(x>=0&&y>=0&&xz))
        return true;
    return false;
}
int main(){
    node roate[120][120];
    int i;
    while(~scanf("%d %d",&a,&b)){
        memset(roate,0,sizeof(roate));
        char Map[120][120]={'\0'};
        memset(Map,0,sizeof(Map));
        memset(vis,0,sizeof(vis));
        for(i=0;i q;
        while(!q.empty())
            q.pop();
        start.x=0;
        start.y=0;
        start.time=0;
        q.push(start);
        while(!q.empty()){
            start=q.front();
            q.pop();
            for(i=0;i<4;i++){
                temp.x=turn[i][0]+start.x;
                temp.y=turn[i][1]+start.y;
                if(Map[temp.x][temp.y]=='.')
                    temp.time=start.time+1;
                if(Map[temp.x][temp.y]<='9'&&Map[temp.x][temp.y]>='1')
                    temp.time=start.time+Map[temp.x][temp.y]-'0'+1;
                if(Map[temp.x][temp.y]=='.'&&check(temp.x,temp.y,temp.time)){
                    vis[temp.x][temp.y]=temp.time;
                    q.push(temp);
                    roate[temp.x][temp.y]=start;
                }
                if(Map[temp.x][temp.y]<='9'&&Map[temp.x][temp.y]>='1'&&check(temp.x,temp.y,temp.time)){
                    vis[temp.x][temp.y]=temp.time;
                    q.push(temp);
                    roate[temp.x][temp.y]=start;
                }
            }
        }
        if(vis[a-1][b-1]==0)
            printf("God please help our poor hero.\n");
        else{
            printf("It takes %d seconds to reach the target position, let me show you the way.\n",vis[a-1][b-1]);
            stackv;
            while(!v.empty())
                v.pop();
            start.x=a-1;start.y=b-1;start.time=vis[a-1][b-1];
            while(!(start.x==0&&start.y==0)){
                v.push(start);
                start = roate[start.x][start.y];
            }
            start.x=0,start.y=0,start.time=0;
            v.push(start);int flag=1;
            while(!(v.top().x==a-1&&v.top().y==b-1)){
                int time1=v.top().time;
                printf("%ds:(%d,%d)->",flag,v.top().x,v.top().y);
                v.pop();
                printf("(%d,%d)\n",v.top().x,v.top().y);
                flag++;
                int lzk=0;
                while(v.top().time-time1-lzk!=1){
                    printf("%ds:FIGHT AT (%d,%d)\n",flag,v.top().x,v.top().y);
                    flag++;lzk++;
                }
            }
        }printf("FINISH\n");
    }
}
这个题喃,要把VIS赋值当前所花的时间,为啥要这么做呢,与前面那个题可不一样,这个题其实与BFS利用队列的原理有关系,本来是到时候通过Front()获取的元素就应该是最早的到达终点的情况,可是打怪就破坏了这个,在没有打怪的情况下不论怎么走每次都是走1s,但是打怪会走多于1s,就破坏了队列自己带来的优势,所以没有用优先队列的情况下,就要赋予VIS实际意义,每一次走过这个点就要判断是否走过,如果走过花费的时间是不是最少,不是就更新这个情况,所以呢,需要把队列所有都跑完直到队列变空,大概思想就是这样,还有一点最重要的,就是记录路径,这个也很复杂,我是用一个二维数组记录的,然后遇到一个问题,这个是倒着的,我们需要倒序输出,这里用了STL的Stack,利用了栈的先进先出。

诡异的楼梯

又是一个类型的题

剩下有空再写

你可能感兴趣的:(BFS)