机试笔记-5

1.广度优先搜索BFS

从起点开始一层一层的扩散出去,要实现这个一层一层的扩散就要用到队列的先进先出的思想,所以一般我们都用队列来实现广度优先搜索算法。
题目描述:小 A 同学现在被困在了一个迷宫里面,他很想从迷宫中走出来,他可以 向上、向下、向左、向右移动、每移动一格都需要花费 1 秒的时间,不能够走到 边界之外。假设小 A 现在的位置在 S,迷宫的出口在 E,迷宫可能有多个出口。 问小 A 想要走到迷宫出口最少需要花费多少秒?
输入样例#:
3 3
S*#
**#
#*E
0 0
输出样例#:
4
const int N = 105;

char mpt[N][N];
int vis[N][N];
int dir[4][2] = {0,1,1,0,0,-1,-1,0};

struct node{
    int x,y;
    int step;
};

//广度优先搜索求解
int bfs(int sx,int sy){
    memset(vis,0,sizeof(vis));
    queue<node> q; //使用数列维护层层发散的优先级
    q.push(node{sx,sy,0});
    vis[sx][sy] = 1 ;
    int ans = -1;
    
    while(!q.empty()){
        node now = q.front();
        q.pop();
        if(mpt[now.x][now.y] == 'E'){
            //找到终点
            ans = now.step;
            break;
        }
        
        for(int i=0;i<4;i++){
            //上下左右四个方向
            int nx = now.x + dir[i][0];
            int ny = now.y + dir[i][1];
            if((mpt[nx][ny] == '*' or mpt[nx][ny] == 'E')and vis[nx][ny] == 0 ){
                q.push(node{nx,ny,now.step+1});
                vis[nx][ny] = 1;
            }
        }
    }
    
    return ans;
}

int main()
{
    int h,w;
    while(scanf("%d%d",&h,&w) != EOF){
        if(h ==0 and w ==0) break;
        int sx = 0, sy = 0;
        memset(mpt,1,sizeof(mpt));
        
        for(int i=1;i<=h;i++){
            scanf("%s",mpt[i] + 1);
            for(int j = 1;j<=w;j++){
                //记录起点坐标
                if(mpt[i][j] == 'S') sx = i , sy = j ; 
            }
        }
        
        int ans = bfs(sx,sy);
        printf("%d\n",ans);
    }
}

递归应用:汉诺塔

题目描述:
(n 阶 Hanoi 塔问题)假设有三个分别命名为 A、B、C 的塔座,在塔座 A 上插有 n(n<20)个直径大小各不相同、依小到大编号为 1,2,…,n 的圆盘。现要求将 A 轴上的 n 个圆盘移至塔座 C上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则: 1)每次只能移动一个圆盘; 2)圆盘可以插在 A、B、C 中的任一塔座上; 3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。 请通过编程来打印出移动的步骤。
输入样例#:
5
2
0
输出样例#:
A-->C A-->B C-->B A-->C B-->A
B-->C A-->C A-->B C-->B C-->A
B-->A C-->B A-->C A-->B C-->B
A-->C B-->A B-->C A-->C B-->A
C-->B C-->A B-->A B-->C A-->C
A-->B C-->B A-->C B-->A B-->C
A-->C
A-->B A-->C B-->C
int step; //移动步数

void Hano(int n,char a,char b,char c){
    if(n==1){
        if((step+1)%5==0) cout << a << "-->" << c << endl;
        else cout << a << "-->" << c << " ";
        step++;
        return;
    }
    Hano(n-1,a,c,b);
    Hano( 1 ,a,b,c);
    Hano(n-1,b,a,c);
}

int main(){
    int n;
    while(cin >> n){
        if(n == 0) break;
        step = 0;
        Hano(n,'A','B','C');
        cout << endl;
    }
}

深度优先搜索 DFS

深度优先搜索的实现形式就是递归,如果把递归的流程画出来可以得到一颗递归树,其实就是一个多叉树。
简单来说, BFS 和 DFS 到底有什么区别呢?
对于一棵二叉树,
BFS 就是二叉树的层次遍历,一层一层的扩展下去。
DFS 就是二叉树的中序遍历,一条路走到底,然后回溯走第二条,直到所有路都走完。
DFS 一般情况下效率不如 BFS,

题目描述:小 A 同学现在被困在了一个迷宫里面,他很想从迷宫中走出来,他可以 向上、向下、向左、向右移动、每移动一格都需要花费 1 秒的时间,不能够走到 边界之外。假设小 A 现在的位置在 S,迷宫的出口在 E,迷宫可能有多个出口。 问小 A 想要走到迷宫出口最少需要花费多少秒?

输入样例#:
3 3
S*#
**#
#*E
0 0
输出样例#:
4

用DFS会超时,但写出来供读者与BFS进行比较

using namespace std;

const int N = 105;

char mpt[N][N];
int vis[N][N];
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
int ans;

//深度优先搜索求解
void dfs(int x,int y,int step){
    if(step >= ans) return; //当步数超过答案就停止
    if(mpt[x][y] == 'E'){
        //找到终点
        ans = min(ans,step);
        return;
    }
    
    for(int i=0;i<4;i++){
        //上下左右四个方向
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if((mpt[nx][ny] == '*' or mpt[nx][ny] == 'E')and vis[nx][ny] == 0 ){
            vis[nx][ny] = 1;
            dfs(nx,ny,step+1);
            vis[nx][ny] = 0;  
        }
    }
}

int main()
{
    int h,w;
    while(scanf("%d%d",&h,&w) != EOF){
        if(h ==0 and w ==0) break;
        int sx = 0, sy = 0;
        memset(mpt,0,sizeof(mpt));
        memset(vis,0,sizeof(vis));
        
        for(int i=1;i<=h;i++){
            scanf("%s",mpt[i] + 1);
            for(int j = 1;j<=w;j++){
                //记录起点坐标
                if(mpt[i][j] == 'S') sx = i , sy = j ; 
            }
        }
        ans = 99999999;
        dfs(sx,sy,0);
        printf("%d\n",ans);
    }
}

石油存储:公司在一个时刻调查一个矩形区域,并且创建成一个个的格子用来表示众多正方形块。它然后使用测定设备单个的分析每块区域,决定是否有石油。一块有石油小区域被称为一个 pocket,假设两个 pocket 是相邻的,然后他们就是相同石油块的一部分,石油块可能非常的大并且包涵很多的 pocket。你的任务就是在一个网格中存在多少个石油块。输入首先给出图的大小,然后给出这个图。*代表没有石油,@代表存在石油。输出每种情况下石油块的个数。

输入样例#:
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0
输出样例#:
2
其实就是搜索有多少个@块,有 8 个方向,我们直接使用 DFS 搜索即可
const int N = 105;

char mpt[N][N];
int vis[N][N];
int dir[8][2] = {1,0,0,-1,-1,0,0,1,1,1,1,-1,-1,1,-1,-1};

//深度优先搜索求解
int dfs(int x,int y){
    vis[x][y] = 1;
    for(int i=0;i<8;i++){
        //8个方向
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if(mpt[nx][ny] == '@' and vis[nx][ny] == 0){
            dfs(nx,ny);
        }
    }
}

int main()
{
    int h,w;
    while(scanf("%d%d",&h,&w) != EOF){
        if(h ==0 and w ==0) break;
        int sx = 0, sy = 0;
        memset(mpt,0,sizeof(mpt));
        memset(vis,0,sizeof(vis));
        
        for(int i=1;i<=h;i++){
            scanf("%s",mpt[i] + 1);
        }
        int ans = 0;
        for(int i = 1; i<=h;i++){
            for(int j = 1;j <=w;j++){
                if(vis[i][j] == 0 and mpt[i][j] =='@'){
                    ans ++;
                    dfs(i,j);
                }
            }
        }
        printf("%d\n",ans);
    }
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值