拯救oibh总部题解

这里附上题目链接:拯救oibh总部
在这里插入图片描述在这里插入图片描述

这是一道十分显然的搜索题!!!

思路解析

题意转换

洪水应该是从地图边界向内渗透,但围墙 * 会将洪水挡住。也就是说洪水只能沿着没有围墙 * 的路径向内渗透

我们可以得到如下结论:
若一块重要区域0能被洪水渗透,说明该重要区域0与地图边界之间至少有1条路径

于是有2种搜索方向:

  1. 从外向内搜:
    从地图的4条边界上的重要区域0出发,向内搜索,将搜索路径上的重要区域0全部用围墙 * 覆盖(因为这些0是可以通到边界的)。若遇到围墙 * ,则说明此条路径不通。最后遍历整个地图,计算出剩余的重要区域0;

  2. 从内向外搜:
    从地图上的每个未被标记的重要区域0出发向外搜索,将搜索路径上的所有重要区域0标记为已访问
    ①若能到达边界,则说明本次搜索中访问的所有重要区域0都会被洪水淹没,将本次搜索记录下所标记的重要区域0的总数sum清零;
    ②若不能到达边界,则记录下所标记的重要区域0的总数sum,最后将这些总数相加。(想想为什么不能将搜索路径上的重要区域全部用围墙 * 覆盖???)

1.DFS——深度优先搜索

(1) 从外向内搜

AC代码:

#include <stdio.h>
#include <stdlib.h>

int n,m;//给出的地图有n行m列
char map[500][505];
int location[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//4个方位

int check(int round,int colume)//检查
{
    if(round>=0&&round<n&&colume>=0&&colume<m)//若坐标未越界
    {
        return 1;
    }
    return 0;//返回假值
}

int DFS(int round,int colume)
{
    int i,x,y;
    if(!check(round,colume))//若坐标越界
    {
        return 0;
    }
    if(map[round][colume]=='*')//若遇到围墙 *
    {
        return 0;//说明此条路径不通
    }
    map[round][colume]='*';//将搜索路径上的重要区域全部用围墙 * 覆盖
    for(i=0;i<4;i++)//沿四个方向继续搜索
    {
    	//计算新坐标
        x=round+location[i][0];
        y=colume+location[i][1];
        DFS(x,y);
    }
    return 0;
}

int main()
{
    int i,j,sum=0;
    //输入数据
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        scanf("%s",map[i]);
    }
    //沿外边界搜索
    if(n>1)
    {
        for(j=0;j<m;j++)
        {
        	//n>1说明地图至少有2行
            DFS(0,j);//上边界
            DFS(n-1,j);//下边界
        }
    }
    else
    {
        for(j=0;j<m;j++)
        {
            DFS(0,j);
        }
    }
    for(i=1;i<n-1;i++)//从左右边界出发
    {
        DFS(i,0);
        DFS(i,m-1);
    }
    //遍历整个地图,计算剩余的重要区域0
    for(i=0;i<n;i++)
    {
        for(j=0;j<m;j++)
        {
            if(map[i][j]=='0')
            {
                sum++;
            }
        }
    }
    //输出结果
    printf("%d",sum);
    return 0;
}

在这里插入图片描述
(2)从内向外搜

AC代码:

#include <stdio.h>
#include <stdlib.h>

char map[500][505];//地图
int visit[500][505];//标记数组
int n,m,sign,sum;//给出的地图有n行m列
int location[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//4个方位

int check(int round,int colume)//检查
{
    if(round>0&&round<n-1&&colume>0&&colume<m-1)//若坐标未到达边界
    {
        return 1;
    }
    return 0;//返回假值
}

int DFS(int round,int colume)
{
    int i,x,y;
    for(i=0;i<4;i++)//沿四个方向继续搜索
    {
        x=round+location[i][0];
        y=colume+location[i][1];
        if((!check(x,y))&&map[x][y]=='0')//若能到达边界上的重要区域0
        {
            sign=1;
            continue;
        }
        if(map[x][y]=='*'||!check(x,y)||visit[x][y])
        {
            continue;
        }
        visit[x][y]=1;//将未访问的此格标记为已访问
        sum++;
        DFS(x,y);
    }
    return 0;
}

int main()
{
    int i,j,cnt=0;
    //输入数据
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        scanf("%s",map[i]);
    }
    //
    for(i=1;i<n-1;i++)
    {
        for(j=1;j<m-1;j++)
        {
            if(map[i][j]=='0'&&!visit[i][j])
            {
                visit[i][j]=1;//标记为已访问
                sum=1;
                sign=0;
                DFS(i,j);//开始搜索
                if(sign)//若能到达边界
                {
                    sum=0;
                }
                cnt+=sum;
            }
        }
    }
    //输出结果
    printf("%d",cnt);
    return 0;
}

在这里插入图片描述

							~~分割线~~ 

实际上,采用这种搜索方向也可以不使用标记数组。这时,我们只需要(逐行逐列地)从每一个重要区域出发进行试探。若发现不能到达边界,则说明幸存的重要区域加一。

//逐行逐列找重要区域
    for(i=0;i<n;i++)
    {
        for(j=0;j<m;j++)
        {
            if(map[i][j]=='0')
            {
                DFS(i,j);
                if(!sign)//若不能到达边界
                {
                    sum++;//幸存的重要区域加一
                }
                sign=0;//将标志复原
            }
        }
    }

完整代码

#include <stdio.h>
#include <stdlib.h>

int n,m,sign;//给出的地图有n行m列
char map[500][505];
int location[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//4个方位

int check(int round,int colume)//检查
{
    if(round>0&&round<n-1&&colume>0&&colume<m-1)//若坐标未到达边界
    {
        return 1;
    }
    return 0;//返回假值
}

int DFS(int round,int colume)
{
    int i,x,y;
    if(!check(round,colume))//若能到达边界
    {
        sign=1;
        return 0;
    }
    if(map[round][colume]=='*')
    {
        return 0;
    }
    for(i=0;i<4;i++)//沿四个方向继续搜索
    {
        x=round+location[i][0];
        y=colume+location[i][1];
        DFS(x,y);
    }
    return 0;
}

int main()
{
    int i,j,sum=0;
    //输入数据
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        scanf("%s",map[i]);
    }
    //逐行逐列找重要区域
    for(i=0;i<n;i++)
    {
        for(j=0;j<m;j++)
        {
            if(map[i][j]=='0')
            {
                DFS(i,j);
                if(!sign)//若不能到达边界
                {
                    sum++;//幸存的重要区域加一
                }
                sign=0;//将标志复原
            }
        }
    }
    //输出结果
    printf("%d",sum);
    return 0;
}

只不过,因为没有剪枝,这样内存会过大!!!(答案是正确的
在这里插入图片描述

2.BFS——广度优先搜索

(1).从外向内搜
AC代码:

#include <stdio.h>
#include <stdlib.h>

int n,m;//给出的地图有n行m列
char map[500][505];//地图
int location[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//4个方位

struct box//box意为方格
{
    int x;
    int y;
}queue[25005];

int check(int round,int colume)//检查
{
    if(round>=0&&round<n&&colume>=0&&colume<m)//若坐标未越界且
    {
        return 1;
    }
    return 0;//返回假值
}

int BFS(int round,int colume)
{
    int i,x,y;
    int head=0,tail=0;//构建队首、队尾
    //第一个结点从队尾入队
    queue[0].x=round;
    queue[0].y=colume;
    map[round][colume]='*';
    tail++;
    while(head<tail)
    {
        for(i=0;i<4;i++)
        {
            //计算新结点坐标
            x=queue[head].x+location[i][0];
            y=queue[head].y+location[i][1];
            if(!check(x,y))//若坐标不合格
            {
                continue;
            }
            if(map[x][y]=='*')//围墙不入队
            {
                continue;
            }
            //子结点入队
            queue[tail].x=x;
            queue[tail].y=y;
            //
            map[x][y]='*';
            tail++;
        }
        head++;//所有子结点都入队的父结点出队
    }
    return 0;
}

int main()
{
    int i,j,sum=0;
    //输入数据
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        scanf("%s",map[i]);
    }
    //沿外边界向内搜索
    if(n>1)
    {
        for(j=0;j<m;j++)
        {
            if(map[0][j]!='*')
            {
                BFS(0,j);
            }
            if(map[n-1][j]!='*')
            {
                BFS(n-1,j);
            }
        }
    }
    else
    {
        for(j=0;j<m;j++)
        {
            if(map[0][j]!='*')
            {
                BFS(0,j);
            }
        }
    }
    for(i=1;i<n-1;i++)
    {
        if(map[i][0]!='*')//不能从围墙出发开始搜索
        {
            BFS(i,0);
        }
        if(map[i][m-1]!='*')//不能从围墙出发开始搜索
        {
            BFS(i,m-1);
        }
    }
    //遍历整个地图,计算结果
    for(i=0;i<n;i++)
    {
        for(j=0;j<m;j++)
        {
            if(map[i][j]=='0')//若有幸存的重要区域
            {
                sum++;
            }
        }
    }
    //输出结果
    printf("%d",sum);
    return 0;
}

在这里插入图片描述
(2).从内向外搜

AC代码:

#include <stdio.h>
#include <stdlib.h>

char map[500][505];
int visit[500][505];
int n,m,sign,sum;//给出的地图有n行m列
int location[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//4个方位

struct box
{
    int x,y;
}queue[250030];

int check(int round,int colume)//检查
{
    if(round>0&&round<n-1&&colume>0&&colume<m-1)//若坐标未到达边界
    {
        return 1;
    }
    return 0;//返回假值
}

int BFS(int round,int colume)
{
    int i,x,y;
    int head=0,tail=0;//构建队首、队尾
    //第一个结点从队尾入队
    queue[tail].x=round;
    queue[tail].y=colume;
    tail++;
    while(head<tail)
    {
        for(i=0;i<4;i++)
        {
            x=queue[head].x+location[i][0];
            y=queue[head].y+location[i][1];
            if((!check(x,y))&&map[x][y]=='0')//若能到达边界上的重要区域0
            {//边界上的重要区域不能入队
                sign=1;//转换标记
                continue;
            }
            if(map[x][y]=='*'||visit[x][y])//这里不用再对(x,y)做坐标检查
            {
                continue;
            }
            //重要区域0入队
            queue[tail].x=x;
            queue[tail].y=y;
            tail++;
            visit[x][y]=1;//将未访问的此格标记为已访问
            sum++;
        }
        head++;//所有子结点都入队的头结点出队
    }
    return 0;
}

int main()
{
    int i,j,cnt=0;
    //输入数据
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        scanf("%s",map[i]);
    }
    //因为是从内向外搜索,所以从内层开始搜索
    for(i=1;i<n-1;i++)
    {
        for(j=1;j<m-1;j++)
        {
            if(map[i][j]=='0'&&!visit[i][j])
            {
            sum=1;
                sign=0;
                visit[i][j]=1;//标记为已访问
                BFS(i,j);//开始搜索
                if(sign)//若能到达边界
                {
                    sum=0;
                }
                cnt+=sum;//累加
            }
        }
    }
    //输出结果
    printf("%d",cnt);
    return 0;
}

在这里插入图片描述

不当之处,敬请斧正……

发布了13 篇原创文章 · 获赞 0 · 访问量 249

猜你喜欢

转载自blog.csdn.net/ZhuhaoNan134/article/details/105150894
今日推荐