BFS_FloodFill模型_山峰和山谷(POI2007)

独自空忆成欢 提交于 2020-02-17 16:11:16

历时两周半左右的动态规划集中学习告一段落,后面会继续补充动态规划相关题目题解和想法。

今天开始学习搜索。

宽度(广度)优先搜索的第一个经典模型——Flood Fill,实际上就是通过BFS在一张图中寻找连通块的模型。

题目:FGD小朋友特别喜欢爬山,在爬山的时候他就在研究山峰和山谷。
为了能够对旅程有一个安排,他想知道山峰和山谷的数量。
给定一个地图,为FGD想要旅行的区域,地图被分为 n×nn×n 的网格,每个格子 (i,j)(i,j) 的高度 w(i,j)w(i,j) 是给定的。
若两个格子有公共顶点,那么它们就是相邻的格子,如与 (i,j)(i,j) 相邻的格子有(i1,j1),(i1,j),(i1,j+1),(i,j1),(i,j+1),(i+1,j1),(i+1,j),(i+1,j+1)(i−1,j−1),(i−1,j),(i−1,j+1),(i,j−1),(i,j+1),(i+1,j−1),(i+1,j),(i+1,j+1)
我们定义一个格子的集合 SS 为山峰(山谷)当且仅当:
1.SS 的所有格子都有相同的高度。
2.SS 的所有格子都连通。
3.对于 ss 属于 SS,与 ss 相邻的ss′不属于 SS,都有 ws>wsws>ws′(山峰),或者 ws<wsws<ws′(山谷)。
如果周围不存在相邻区域,则同时将其视为山峰和山谷。
你的任务是,对于给定的地图,求出山峰和山谷的数量,如果所有格子都有相同的高度,那么整个地图即是山峰,又是山谷。
数据范围:1n1000,1≤n≤1000,0w1090≤w≤109

解法:BFS最基础的应用之一,思路很简单,就是从一个为访问过的点出发,加入队头,进行BFS,遍历周围的点,合法的加入队列尾部,直到队列为空,有两点要注意的:
1、不用DFS是因为数据范围最大可能会有一百万的递归栈,防止爆栈,选用BFS;
2、就是处理山谷和山峰是通过在扩展时碰到不一样的高度再来判断即可。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii;

const int N=1010;

int g[N][N],n;
bool v[N][N];
int h,l;
pii q[N*N];

void bfs(int sx,int sy,bool& hi,bool& lo){
    int hh=0,tt=0;
    q[0]={sx,sy};
    while(hh<=tt){
        pii t=q[hh++];
        v[t.x][t.y]=1;
        for(int i=t.x-1;i<=t.x+1;i++)
            for(int j=t.y-1;j<=t.y+1;j++){
                if(i==t.x && j==t.y) continue;
                if(i<=0 || i>n || j<=0 || j>n) continue;
                if(g[i][j]!=g[sx][sy]){
                    if(g[i][j]>g[sx][sy]) hi=true;
                    else lo=true;
                }
                else if(!v[i][j]){
                    q[++tt]={i,j};
                    v[i][j]=1;
                }
            }
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&g[i][j]);
            
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!v[i][j]){
            bool high=false,low=false;
            bfs(i,j,high,low);
            if(!high) h++;
            if(!low) l++;
        }
    
    cout<<h<<" "<<l<<endl;
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!