关于【广度优先搜索】

题目1456:胜利大逃亡

题目描述:

Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.

输入:

输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙。

输出:

对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.

样例输入:
1
3 3 4 20
0 1 1 1
0 0 1 1
0 1 1 1
1 1 1 1
1 0 0 1
0 1 1 1
0 0 0 0
0 1 1 0
0 1 1 0 
样例输出:
11

代码如下:

#include <iostream>
#include <stdio.h>
#include <queue>
 
using namespace std;
 
/*所谓广度优先搜索,即在遍历解答树时使每次状态转移时扩展出尽可能多
的新状态,并且按照各个状态出现的先后顺序依次扩展它们。但是,这样所
需查找的状态是非常多,最坏情况下,因为每个结点都能扩展出6个新结点,
那么仅走10步,其状态数就会达到6^10,需要大量的时间才能依次遍历完这
些状态,所以我们必须采用相应的措施来制约状态的无限扩展,这个方法就
是剪枝*/
 
/*在起点走向终点的最短路径上,到达任意一个中间结点所用的时间都是起
点到达这个结点的最短时间,那么我们所要查找的答案比不可能由该状态进
行若干次扩展后得到*/
 
/*例如:当我们第一次查找到包含点(x,y,z)的坐标状态后,其后查找到的
任意包含该坐标的状态都不必扩展*/
 
bool mark[50][50][50];  //标记数组
int maze[50][50][50];   //保存立方体信息
 
struct N{
    int x;
    int y;
    int z;
    int t;
};
 
queue<N> Q;            //队列,队列中的元素为状态
int go[][3]={          //坐标变换数组,由坐标(x,y,z)扩展得到的新坐标均可
        {1,0,0},       //通过(x+go[i][0],y+go[i][1],z+go[i][2])得到
        {-1,0,0},
        {0,1,0},
        {0,-1,0},
        {0,0,1},
        {0,0,-1}
        };
 
int BFS(int a,int b,int c){    //广度优先搜索,返回其最少耗时
    while(Q.empty()==false){   //当队列中仍有元素可以扩展时循环
        N now=Q.front();       //得到队头状态
        Q.pop();               //从队列中弹出队头状态
        for(int i=0;i<6;i++){  //依次扩展其6个相邻结点
            int nx=now.x+go[i][0];
            int ny=now.y+go[i][1];
            int nz=now.z+go[i][2];
            if(nx<0||nx>=a||ny<0||ny>=b||nz<0||nz>=c)  //若新坐标在立方体外,则丢弃该坐标
                continue;
            if(maze[nx][ny][nz]==1)     //若该位置为墙,则丢弃该坐标
                continue;
            if(mark[nx][ny][nz]==true)  //若包含该坐标的状态已经被得到过,则丢弃该状态
                continue;
            N temp;                     //新的状态
            temp.x=nx;
            temp.y=ny;
            temp.z=nz;                  //新状态包含的坐标
            temp.t=now.t+1;             //新状态的耗时
            Q.push(temp);               //将新状态加入到队列
            mark[nx][ny][nz]=true;      //标记该坐标
            if(nx==a-1&&ny==b-1&&nz==c-1)
                return temp.t;
        }
    }
    return -1;
}
 
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int a,b,c,t;
        scanf("%d%d%d%d",&a,&b,&c,&t);     //输入
        for(int i=0;i<a;i++){
            for(int j=0;j<b;j++){
                for(int k=0;k<c;k++){
                    scanf("%d",&maze[i][j][k]);      //输入立方体信息
                    mark[i][j][k]=false;             //初始化标记数组
                }
            }
        }
        while(Q.empty()==false)          //清空队列
            Q.pop();
        mark[0][0][0]=true;              //标记起点
        N temp;
        temp.x=temp.y=temp.z=temp.t=0;   //初始状态
        Q.push(temp);                    //将初始状态放入队列
        int rec=BFS(a,b,c);              //广度优先搜索
        if(rec<=t)
            printf("%d
",rec);          //若所需时间符合条件,则输出
        else
            printf("-1
");              //否则输出-1
    }
    return 0;
}
 
/**************************************************************
    Problem: 1456
    User: lcyvino
    Language: C++
    Result: Accepted
    Time:30 ms
    Memory:2132 kb
****************************************************************/

题目1457:非常可乐

题目描述:

大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升(正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。

输入:

三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。

输出:

如果能平分的话请输出最少要倒的次数,否则输出"NO"。

样例输入:
7 4 3
4 1 3
0 0 0
样例输出:
NO
3

代码如下:
#include <stdio.h>
#include <queue>
 
using namespace std;
 
struct N{
    int a,b,c;    //每个杯子中可乐的体积
    int t;        //得到该体积倾倒的次数
};
 
queue<N> Q;
bool mark[101][101][101];
 
void AtoB(int &a,int sa,int &b,int sb){    //由容积为sa的杯子倒往容积为sb的杯子
    if(sb-b>=a){
//        a=0;
//        b=a+b;   顺序不能颠倒!!
        b=a+b;
        a=0;
    }else{
        a=a-(sb-b);
        b=sb;
    }
}
 
int BFS(int s,int n,int m){
    while(Q.empty()==false){
        N now=Q.front();
        Q.pop();
        int a,b,c;                  //a,b,c临时保存三个杯子中的可乐体积
        a=now.a;
        b=now.b;
        c=now.c;
        AtoB(a,s,b,n);              //由a倒向b
        if(mark[a][b][c]==false){   //若该体积组尚未出现
            mark[a][b][c]=true;     //标记该体积组
            N temp;
            temp.a=a;
            temp.b=b;
            temp.c=c;
            temp.t=now.t+1;         //生成新的状态
            if(a==s/2&&b==s/2)
                return temp.t;
            if(a==s/2&&c==s/2)
                return temp.t;
            if(b==s/2&&c==s/2)
                return temp.t;      //若该状态已经为平分状态,则直接返回该状态的耗时
            Q.push(temp);           //否则放入队列
        }
 
        a=now.a;
        b=now.b;
        c=now.c;                    //重置a,b,c为倾倒前的体积
        AtoB(b,n,a,s);              //由b倒向a
        if(mark[a][b][c]==false){
            mark[a][b][c]=true;
            N temp;
            temp.a=a;
            temp.b=b;
            temp.c=c;
            temp.t=now.t+1;
            if(a==s/2&&b==s/2)
                return temp.t;
            if(a==s/2&&c==s/2)
                return temp.t;
            if(b==s/2&&c==s/2)
                return temp.t;
            Q.push(temp);
        }
 
        a=now.a;
        b=now.b;
        c=now.c;
        AtoB(a,s,c,m);     //由a倒向c
        if(mark[a][b][c]==false){
            mark[a][b][c]=true;
            N temp;
            temp.a=a;
            temp.b=b;
            temp.c=c;
            temp.t=now.t+1;
            if(a==s/2&&b==s/2)
                return temp.t;
            if(a==s/2&&c==s/2)
                return temp.t;
            if(b==s/2&&c==s/2)
                return temp.t;
            Q.push(temp);
        }
 
        a=now.a;
        b=now.b;
        c=now.c;
        AtoB(c,m,a,s);     //由c倒向a
        if(mark[a][b][c]==false){
            mark[a][b][c]=true;
            N temp;
            temp.a=a;
            temp.b=b;
            temp.c=c;
            temp.t=now.t+1;
            if(a==s/2&&b==s/2)
                return temp.t;
            if(a==s/2&&c==s/2)
                return temp.t;
            if(b==s/2&&c==s/2)
                return temp.t;
            Q.push(temp);
        }
 
        a=now.a;
        b=now.b;
        c=now.c;
        AtoB(b,n,c,m);     //由b倒向c
        if(mark[a][b][c]==false){
            mark[a][b][c]=true;
            N temp;
            temp.a=a;
            temp.b=b;
            temp.c=c;
            temp.t=now.t+1;
            if(a==s/2&&b==s/2)
                return temp.t;
            if(a==s/2&&c==s/2)
                return temp.t;
            if(b==s/2&&c==s/2)
                return temp.t;
            Q.push(temp);
        }
 
        a=now.a;
        b=now.b;
        c=now.c;
        AtoB(c,m,b,n);     //由c倒向b
        if(mark[a][b][c]==false){
            mark[a][b][c]=true;
            N temp;
            temp.a=a;
            temp.b=b;
            temp.c=c;
            temp.t=now.t+1;
            if(a==s/2&&b==s/2)
                return temp.t;
            if(a==s/2&&c==s/2)
                return temp.t;
            if(b==s/2&&c==s/2)
                return temp.t;
            Q.push(temp);
        }
    }
    return -1;
}
 
int main()
{
    int s,n,m;
    while(scanf("%d%d%d",&s,&n,&m)!=EOF){
        if(s==0)
            break;
        if(s%2==1){
            printf("NO
");
            continue;
        }
        for(int i=0;i<=s;i++){
            for(int j=0;j<=n;j++){
                for(int k=0;k<=m;k++){
                    mark[i][j][k]=false;
                }
            }
        }
        N temp;
        temp.a=s;
        temp.b=0;
        temp.c=0;
        temp.t=0;
        while(Q.empty()==false)
            Q.pop();
        Q.push(temp);
        mark[s][0][0]=true;
        int rec=BFS(s,n,m);
        if(rec==-1)
            printf("NO
");
        else
            printf("%d
",rec);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1457
    User: lcyvino
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:2528 kb
****************************************************************/

闯迷宫

题目描述:

sun所在学校每年都要举行电脑节,今年电脑节有一个新的趣味比赛项目叫做闯迷宫。
sun的室友在帮电脑节设计迷宫,所以室友就请sun帮忙计算下走出迷宫的最少步数。
知道了最少步数就可以辅助控制比赛难度以及去掉一些没有路径到达终点的map。
比赛规则是:从原点(0,0)开始走到终点(n-1,n-1),只能上下左右4个方向走,只能在给定的矩阵里走。

输入:

输入有多组数据。
每组数据输入n(0<n<=100),然后输入n*n的01矩阵,0代表该格子没有障碍,为1表示有障碍物。
注意:如果输入中的原点和终点为1则这个迷宫是不可达的。

输出:

对每组输入输出该迷宫的最短步数,若不能到达则输出-1。

样例输入:
2
0 1
0 0
5
0 0 0 0 0
1 0 1 0 1
0 0 0 0 0
0 1 1 1 0
1 0 1 0 0
样例输出:
2
8

Code:
#include <cstdio>
#include <queue>
 
using namespace std;
 
struct Status{
    int x;
    int y;
    int t;
};
 
const int arrSize=110;
int maze[arrSize][arrSize];
bool mark[arrSize][arrSize];
bool canAccess=true;
queue<Status> Q;
int go[][2]={
    {-1,0},
    {1,0},
    {0,1},
    {0,-1}
};
 
int BFS(int n){
    while(Q.empty()==false){
        Status now=Q.front();
        Q.pop();
        for(int i=0;i<4;++i){
            int nx=now.x+go[i][0];
            int ny=now.y+go[i][1];
            int nt=now.t+1;
            if(nx<0||nx>=n||ny<0||ny>=n)
                continue;
            if(maze[nx][ny]==1)
                continue;
            if(mark[nx][ny]==false)
                continue;
            if(nx==n-1&&ny==n-1)
                return nt;
            Status tmp;
            tmp.x=nx;
            tmp.y=ny;
            tmp.t=nt;
            Q.push(tmp);
            mark[nx][ny]=false;
        }
    }
    return -1;
}
 
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){   //初始化
        for(int i=0;i<n;++i){
            for(int j=0;j<n;++j){
                mark[i][j]=true;
                maze[i][j]=0;
            }
        }
        while(Q.empty()==false)
            Q.pop();
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j)
                scanf("%d",&maze[i][j]);
        if(maze[0][0]==1||maze[n-1][n-1]==1)
            printf("-1
");
        else{
            Status tmp;
            tmp.x=0;
            tmp.y=0;
            tmp.t=0;
            Q.push(tmp);
            mark[0][0]=false;
            int ans=BFS(n);
            if(ans==-1)
                printf("-1
");
            else
                printf("%d
",ans);
        }
    }
    return -1;
}
 
/**************************************************************
    Problem: 1335
    User: lcyvino
    Language: C++
    Result: Accepted
    Time:100 ms
    Memory:1112 kb
****************************************************************/
原文地址:https://www.cnblogs.com/Murcielago/p/4092941.html