洛谷P1256 显示图像

题面:

解题:

  1. 确定算法:

题中的数据就像一张二维的,上面布满了0和1,

而我们的任务是要寻找这幅图中每个0相对其最近的1的距离,这不免让我们联想图搜索算法。

观察数据规模:N,M≤182,很遗憾,我们的DFS顺利抱回8个WA!(别问我怎么知道的……)

因此,相较于DFS,本题更优秀的算法应该是:

广度优先搜索(BFS)!——层层推进

倘若,你这是你第一次接触BFS,没关系,看到最后的你自然会体悟到其妙趣~

  1. 算法需要的组件

① bool memo[1005][1005]; //储存搜索状态

② int ans[1005][1005] = { 0 }; //ans是老朋友了,答案是一张图,存放到二维数组

③ vector<pair<int, int>>v; //储存对组pair<int,int>的队列v,可谓灵魂

④ 方向数组 //d_x、d_y配套使用,例如坐标(x+d_x[i] , y+d_[i]),i=1时,代表右平移1单位

int d_x[5] = { 0,1,-1,0,0 };

int d_y[5] = { 0,0,0,1,-1 };

⑤边界判断函数 //数组越界可不好玩哦,还是判断一下保险

bool edge(int x, int y)  //保证不越界
{
    if (x <= 0 || y <= 0 || x >= n + 1 || y >= m + 1)return false;  //越界
    return true;  //不越界
}

  1. 实现

读入阶段

由于白色方块的ans默认为0,固不需要搜索,我们在读入数据阶段便进行标记:

memp[ i ][ j ]=true ; //代表不需要搜索 v.push_back(make_pair(i, j)); //导入队列

阶段效果代码如下:

    memset(memo, false, sizeof(memo));   //memo初始化为false
    cin >> n >> m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin >> a[i][j];
            if(a[i][j]=='0'){ }  //黑色,默认为false,未搜索过
            else              //白色,ans一定是0,标记为搜索过,入队
            {
                memo[i][j] = true;  //搜索过了
                v.push_back(make_pair(i, j));
            }
        }

搜索阶段

我们需要遍历我们的队列:v!

方向数组派上用场了!利用方向数组搜索队列元素v[ i ]的上、下、左、右四个方向,

给未搜索过的元素赋ans值,值为v[ i ]ans值+1,因为我们一次只推进一格

别忘了要把搜索过的元素memo值赋为true,标记为已搜索,

还要对其进行入队操作,即v.push_back(make_pair(t_x, t_y)),

这样,它就乖乖地躺在了队列的末尾,由于先来后到原则,

它会等到队列前面的元素都被遍历完后,再轮到,

反复如此,以实现“由白色点的ans=0开始,向外ans=1,ans=2……ans=n”层层推进的效果

阶段效果代码如下:

    int d_x[5] = { 0,1,-1,0,0 };     //方向数组
    int d_y[5] = { 0,0,0,1,-1 };    
    for(int i=0;i<=v.size()-1; i++)   //搜索队列
    {
        for(int j=1;j<=4;j++)        //搜索 上下左右 四个方向
        {
            int t_x = v[i].first + d_x[j];//target,得到判定目标的x、y坐标t_x、t_y
            int t_y = v[i].second + d_y[j];
            if (edge(t_x, t_y) && memo[t_x][t_y] == false) //未搜索过、未越界,搜!
            {
                ans[t_x][t_y] = ans[v[i].first][v[i].second] + 1;
                memo[t_x][t_y] = true;
                v.push_back(make_pair(t_x, t_y));
            }
        }
    }

AC代码奉上:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>

using namespace std;

int n, m;

char a[1005][1005] = { 0 }; //读入
bool memo[1005][1005];      //储存搜索状态
int ans[1005][1005] = { 0 };
vector<pair<int, int>>v;    //储存对组的队列

bool edge(int x, int y)  //判断(x,y)是否越界
{
    if (x <= 0 || y <= 0 || x >= n + 1 || y >= m + 1)return false;  //越界
    return true;  //不越界
}

int main()
{
    memset(memo, false, sizeof(memo));  //默认将memo全部标记为false
    cin >> n >> m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin >> a[i][j];   //我是读入
            if(a[i][j]=='0'){ }  //黑色,默认为false,未搜索过
            else              //白色,ans一定是0,标记为搜索过,入队
            {
                memo[i][j] = true;
                v.push_back(make_pair(i, j));
            }
        }

    int d_x[5] = { 0,1,-1,0,0 };     //方向数组
    int d_y[5] = { 0,0,0,1,-1 };
    for(int i=0;i<=v.size()-1; i++)   //搜索队列
        for(int j=1;j<=4;j++)        //搜索 上下左右 四个方向
        {
            int t_x = v[i].first + d_x[j];
            int t_y = v[i].second + d_y[j];
            if (edge(t_x, t_y) && memo[t_x][t_y] == false) //未搜索过,搜!
            {
                ans[t_x][t_y] = ans[v[i].first][v[i].second] + 1;
                memo[t_x][t_y] = true;
                v.push_back(make_pair(t_x, t_y));
            }
        }

    for(int i=1;i<=n;i++)
    {
        for (int j = 1; j <= m; j++)cout << ans[i][j] << " ";  //输出哈
        cout << endl;
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值