Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions other_algorithms/monge_checker.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <sstream>
#include <string>

// Check whether cost(i, j) is Monge or not
// Complexity: O(nm)
// https://hackmd.io/@tatyam-prime/monge1
template <bool only_upper = false>
std::string check_matrix_monge(auto cost, auto inf, int n, int m) {
if (m < 0) m = n;

auto Detect = [n, m, inf](auto f) -> std::tuple<bool, int, int> {
for (int i = 0; i + 1 < n; ++i) {
for (int j = only_upper ? (i + 2) : 0; j + 1 < m; ++j) {
const auto f00 = f(i, j), f01 = f(i, j + 1), f10 = f(i + 1, j),
f11 = f(i + 1, j + 1);
if (f00 >= inf or f01 >= inf) continue;
if (f00 + f11 > f10 + f01) { return {false, i, j}; }
}
}
return {true, -1, -1};
};

if (auto [is_monge, i, j] = Detect(cost); is_monge) {
return "Monge OK";
} else if (auto [is_anti_monge, ai, aj] = Detect([&cost, inf](int i, int j) {
auto ret = cost(i, j);
return ret == inf ? inf : -ret;
});
is_anti_monge) {
return "Not Monge, but Anti-Monge OK";
} else {
std::stringstream ret;
ret << "Not Monge!\n";
ret << " j=" << std::to_string(j) << " j=" << std::to_string(j + 1) << "\n";
ret << "i=" << std::to_string(i) << " " << cost(i, j) << " " << cost(i, j + 1) << "\n";
ret << "i=" << std::to_string(i + 1) << " " << cost(i + 1, j) << " " << cost(i + 1, j + 1);
return ret.str();
}
}

// Check whether graph weight is Monge or not
// Complexity: O(n^2)
std::string check_dag_monge(auto cost, auto inf, int n) {
return check_matrix_monge<true>(cost, inf, n, n);
}
37 changes: 37 additions & 0 deletions other_algorithms/monge_checker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title: Monge checker
documentation_of: ./monge_checker.hpp
---

与えられた一般の $n \times m$ 行列や $n$ 頂点 DAG の重み行列の Monge 性および Anti-Monge 性を確認し,以下の結果を出力する.

- Monge であった場合, `Monge OK` と出力
- Monge ではないが anti-Monge であった場合, `Not Monge, but Anti-Monge OK` と出力
- Monge でも anti-Monge でもない場合, `Not Monge!` と出力し,続けて Monge 性に反する $2 \times 2$ 小行列を出力

計算量は $O(nm)$ や $O(n^2)$ なので,ジャッジへの提出にこの関数の実行を含めると TLE となりうるので注意.

## 使用方法

行列を `std::vector<std::vector<long long>>` 等の形で直接与えるのではなく, `int` 2 つを引数として重みを返す関数 `cost(int, int)` を引数として与えればよい.

### $n$ 頂点 DAG の辺重み関数の Monge 性判定

```cpp
int n; // 頂点: 0, 1, ..., (n - 1)
using T = long long;
T INF;
auto cost = [&](int i, int j) -> T {
// Return weight of directed edge i->j, or INF if the edge does not exist.
};

cerr << check_dag_monge(cost, INF, n) << endl;
```

## Monge 性の確認方法

隣接する 2 行と 2 列の要素からなる全ての $2 \times 2$ 小行列に対する Monge 性を確認すればよい [1].

## Links

- [1] [[Monge まとめ①] Monge 性とは? - HackMD](https://hackmd.io/@tatyam-prime/monge1)
1 change: 1 addition & 0 deletions other_algorithms/monge_shortest_path.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Cost ret = monge_shortest_path_with_specified_edges(n, l, r, max_weight, f);
- [AtCoder Beginner Contest 218 H - Red and Blue Lamps](https://atcoder.jp/contests/abc218/tasks/abc218_h)
- [東京海上日動プログラミングコンテスト2024(AtCoder Beginner Contest 355) G - Baseball](https://atcoder.jp/contests/abc355/tasks/abc355_g)
- [東北大学プログラミングコンテスト 2022 K - Lebesgue Integral](https://atcoder.jp/contests/tupc2022/tasks/tupc2022_k)
- [Educational Codeforces Round 181 (Rated for Div. 2) F. Timofey and Docker](https://codeforces.com/contest/2125/problem/F)

## Links

Expand Down