登峰造极 题解

一、题目:

二、思路:

首先这题一看就有打暴力的冲动。flood-fill搞一搞,拿到了70分。

那么我们来讲一讲正解。

首先我们将网格图转化成线性图后按高度从大到小排序。然后我们考虑这样两个点\(i,j\),其中i的高度大于j的高度。我们记i能走到的所有点为集合\(S_i\),记j能走到的所有点为集合\(S_j\),那么如果\(S_i\)\(S_j\)有交集,那么j就一定不可能是“登峰造极”。感性理解一下:高山峰能走过的点,低山峰一定能走到。所以\(S_i\)\(S_j\)一旦有交集,必有\(S_i\subseteq S_j\)
.
那么我们按高度从大到小的顺序枚举每个点,标记它能走过的所有点。如果它能到一个已经被标记的点,它就一定不是“登峰造极”,否则就一定是“登峰造极”。

显然,遇到已经被标记的点就不用再搜了,因为它能被比它高的点走到,所以它就也一定不是“登峰造极”。

时间复杂度\(O(n\times m)\)。如果算上排序的话应该是\(O(nmlog_2(nm))\)

三、代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
 
#define LL long long
#define mem(s,v) memset(s,v,sizeof(s))
#define FILEIN(s) freopen(s".in","r",stdin)
#define FILEOUT(s) freopen(s".out","w",stdout)
 
using namespace std;
 
inline LL read(void){
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
 
const int maxn=505;
 
int n,m,ans;
LL d;
 
LL Map[maxn][maxn];

pair<int,int>num[maxn*maxn];

struct Node{
    int x,y,data;
    Node(){}
    Node(int _x,int _y,int _data):x(_x),y(_y),data(_data){}
    inline friend bool operator <(Node a,Node b){
        return a.data>b.data;
    }
}ord[maxn*maxn];
 
int dx[]={0,1,0,-1},dy[]={1,0,-1,0},cnt;

int vis[maxn][maxn];

inline int key(int x,int y){return (x-1)*m+y;}

inline void dot(int K,int &x,int &y){
    x=num[K].first;
    y=num[K].second;
}

inline bool check(int x,int y){
    if(x<1||x>n||y<1||y>m)return false;
    return true;
}
 
void bfs(int stx,int sty){
    queue<int>q;
    q.push(key(stx,sty));
    vis[stx][sty]=++cnt;
    bool flag=false;
    int sum=0;
    while(q.size()){
        int nx,ny,K=q.front();q.pop();dot(K,nx,ny);
        if(Map[nx][ny]==Map[stx][sty])++sum;
        for(register int i=0;i<4;++i){
            int tx=nx+dx[i],ty=ny+dy[i];
            if(check(tx,ty)&&Map[tx][ty]>Map[stx][sty]-d){
                if(vis[tx][ty]&&vis[tx][ty]!=cnt)flag=true;
                else if(!vis[tx][ty]){
                    vis[tx][ty]=cnt;
                    q.push(key(tx,ty));
                }
            }
        }
    }
    if(!flag){
        ans+=sum;
    }
}
 
int main(){
    // FILEIN("dfzj");FILEOUT("dfzj");
    n=read();m=read();d=read();
    for(register int i=1;i<=n;++i){
        for(register int j=1;j<=m;++j){
            Map[i][j]=read();
            ord[key(i,j)]=Node(i,j,Map[i][j]);
            num[key(i,j)].first=i;
            num[key(i,j)].second=j;
        }
    }
    sort(ord+1,ord+n*m+1);
    for(register int i=1;i<=n*m;++i){
        bfs(ord[i].x,ord[i].y);
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2019-07-13 20:29  蓝田日暖玉生烟  阅读(180)  评论(0编辑  收藏  举报