Learning Algorithms

アルゴリズムの勉強メモ

第16回日本情報オリンピック予選 E. 尾根(Ridge)

第16回日本情報オリンピック予選 E. 尾根(Ridge)

E: 尾根 (Ridge) - 第16回日本情報オリンピック 予選(オンライン) | AtCoder

感想

典型的なdfsに落とし込む問題

解法

水が流れる方向に沿って、辺を張る。このとき、出次数が0であるような頂点がそれ以降どこにも水が流れない「谷」である。ある頂点が尾根であるための必要十分条件は、その頂点からスタートして、2つ以上の異なる谷に到達可能であることである。よって、各頂点からdfsをして、そこから到達可能な点が一つならば、その頂点の番号を記録し、2つ以上ある場合はINFなどと記録しておくようなdpで解くことができる。$\ O(hw)\ $。

実装
#include "bits/stdc++.h"
using namespace std;

static const int INF = 0x3f3f3f3f;

vector<int> g[1010101];
bool used[1010101];
int dest[1010101];
int h, w;

void add(int fromy, int fromx, int toy, int tox) {
        g[fromy * w + fromx].push_back(toy * w + tox);
}

void dfs(int v) {
        used[v] = true;
        if (g[v].size() == 0) {
                dest[v] = v;
                return;
        }
        set<int> can;
        for (auto u : g[v]) {
                if (!used[u]) dfs(u);
                can.insert(dest[u]);
        }
        if (can.size() > 1) dest[v] = INF;
        else for (auto c : can) dest[v] = c;
        return;

}

void solve() {
        cin >> h >> w;
        vector<vector<int> > s(h, vector<int> (w));
        for (int y = 0; y < h; y ++) {
                for (int x = 0; x < w; x ++) {
                        cin >> s[y][x];
                }
        }
        for (int y = 0; y < h; y ++) {
                for (int x = 0; x < w - 1; x ++) {
                        if (s[y][x] < s[y][x + 1]) add(y, x + 1, y, x);
                        else add(y, x, y, x + 1);
                }
        }
        for (int x = 0; x < w; x ++) {
                for (int y = 0; y < h - 1; y ++) {
                        if (s[y][x] < s[y + 1][x]) add(y + 1, x, y, x);
                        else add(y, x, y + 1, x);
                }
        }
        for (int i = 0; i < h * w; i ++) if (!used[i]) dfs(i);
        int ans = 0;
        for (int i = 0; i < h * w; i ++) ans += dest[i] == INF;
        cout << ans << endl;
        return;
}

int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        solve();
        return 0;
}