UVa12130/LA3977 Summits

题目链接

        本题是2007年ICPC欧洲区域赛西北赛区G

题意

        给定一个h * w的地图(1\leq w,h\leq 500),每个位置有一个高度值,现在要求出这个图上的峰顶有多少个。峰顶是这样定义的:对于给定d值,一个高度为h的位置,如果它不经过不大于高度为h-d的位置就无法走到更高的山峰,那么它就是峰顶。

分析

        如果数据规模小,对每一个点做dfs即可求解,但是题目交代的数据规模大,需要做优化,优化的思路是贪心加bfs:先将所有点按照高度递减排序,再依次遍历每个点做bfs。

        具体来说,用数组f[w*h]记录每个点在给定d值条件下可以到达的最大高度(初始值全为负,代表未求解且未遍历到)。然后按高度递减排序后依次做dfs遍历,开始时计数cc=1,能到达的最大高度gx = g,初始点入队列,初始点(记其高度为g)在d值限定下可以经过的点v有以下情况:1、f[v] > gx, 说明初始点不是峰顶,gx = f[v];2、f[v] < 0,则加入队列且赋值f[v] = g,并且若h[v] == g,则++cc。bfs结束时:若gx == g,说明本次找到cc个峰顶;否则本次未找到峰顶。

        这里贪心的点在于:所有遍历到的点都是在最大下降高度<d的前提下进行的,将高度降序排列了,后遍历点经过已遍历点时所有遍历过的点必然满足高度限制,所以后遍历到的点走到已遍历的非峰顶的点时能判定出此轮高度不超过初始点的都不是峰顶。

        分析一下时间复杂度:记n=w*h,其实所有bfs做完仍然是O(n)时间复杂度,排序导致整体时间复杂度为O(n*logn)。

AC代码

#include <iostream>
#include <algorithm>
using namespace std;

#define N 252004
int h[N], s[N], f[N], q[N], t, r, c, d;

bool cmp(int i, int j) {
    return h[i] > h[j];
}

int bfs(int u, int g) {
    int head = 0, tail = 1, gd = g-d, cc = 1, gx = g; f[q[0] = u] = g;
    while (head < tail) {
        u = q[head++];
        int x = u/c, y = u%c, v;
        if (x > 0 && h[v = (x-1)*c + y] > gd)
            if (f[v] < 0) {
                if (h[v] == g) ++cc;
                q[tail++] = v; f[v] = g;
            } else gx = max(f[v], gx);
        if (x+1 < r && h[v = (x+1)*c + y] > gd)
            if (f[v] < 0) {
                if (h[v] == g) ++cc;
                q[tail++] = v; f[v] = g;
            } else gx = max(f[v], gx);
        if (y > 0 && h[v = x*c + y-1] > gd)
            if (f[v] < 0) {
                if (h[v] == g) ++cc;
                q[tail++] = v; f[v] = g;
            } else gx = max(f[v], gx);
        if (y+1 < c && h[v = x*c + y+1] > gd)
            if (f[v] < 0) {
                if (h[v] == g) ++cc;
                q[tail++] = v; f[v] = g;
            } else gx = max(f[v], gx);
    }
    if (gx > g) while (tail--) f[q[tail]] = gx;
    return gx > g ? 0 : cc;
}

void solve() {
    cin >> r >> c >> d;
    for (int i=t=0; i<r; ++i) for (int j=0; j<c; ++j) f[s[t] = t] = -1, cin >> h[t++];
    sort(s, s+t, cmp);
    int ans = 0;
    for (int i=0; i<t; ++i) if (f[s[i]] < 0) ans += bfs(s[i], h[s[i]]);
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t; cin >> t;
    while (t--) solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值