Skip to content

Commit e546ae8

Browse files
authored
Merge pull request #380 from hitonanode/monge-checker
add Monge checker
2 parents 6b20059 + a438039 commit e546ae8

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

other_algorithms/monge_checker.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#pragma once
2+
3+
#include <sstream>
4+
#include <string>
5+
6+
// Check whether cost(i, j) is Monge or not
7+
// Complexity: O(nm)
8+
// https://hackmd.io/@tatyam-prime/monge1
9+
template <bool only_upper = false>
10+
std::string check_matrix_monge(auto cost, auto inf, int n, int m) {
11+
if (m < 0) m = n;
12+
13+
auto Detect = [n, m, inf](auto f) -> std::tuple<bool, int, int> {
14+
for (int i = 0; i + 1 < n; ++i) {
15+
for (int j = only_upper ? (i + 2) : 0; j + 1 < m; ++j) {
16+
const auto f00 = f(i, j), f01 = f(i, j + 1), f10 = f(i + 1, j),
17+
f11 = f(i + 1, j + 1);
18+
if (f00 >= inf or f01 >= inf) continue;
19+
if (f00 + f11 > f10 + f01) { return {false, i, j}; }
20+
}
21+
}
22+
return {true, -1, -1};
23+
};
24+
25+
if (auto [is_monge, i, j] = Detect(cost); is_monge) {
26+
return "Monge OK";
27+
} else if (auto [is_anti_monge, ai, aj] = Detect([&cost, inf](int i, int j) {
28+
auto ret = cost(i, j);
29+
return ret == inf ? inf : -ret;
30+
});
31+
is_anti_monge) {
32+
return "Not Monge, but Anti-Monge OK";
33+
} else {
34+
std::stringstream ret;
35+
ret << "Not Monge!\n";
36+
ret << " j=" << std::to_string(j) << " j=" << std::to_string(j + 1) << "\n";
37+
ret << "i=" << std::to_string(i) << " " << cost(i, j) << " " << cost(i, j + 1) << "\n";
38+
ret << "i=" << std::to_string(i + 1) << " " << cost(i + 1, j) << " " << cost(i + 1, j + 1);
39+
return ret.str();
40+
}
41+
}
42+
43+
// Check whether graph weight is Monge or not
44+
// Complexity: O(n^2)
45+
std::string check_dag_monge(auto cost, auto inf, int n) {
46+
return check_matrix_monge<true>(cost, inf, n, n);
47+
}

other_algorithms/monge_checker.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: Monge checker
3+
documentation_of: ./monge_checker.hpp
4+
---
5+
6+
与えられた一般の $n \times m$ 行列や $n$ 頂点 DAG の重み行列の Monge 性および Anti-Monge 性を確認し,以下の結果を出力する.
7+
8+
- Monge であった場合, `Monge OK` と出力
9+
- Monge ではないが anti-Monge であった場合, `Not Monge, but Anti-Monge OK` と出力
10+
- Monge でも anti-Monge でもない場合, `Not Monge!` と出力し,続けて Monge 性に反する $2 \times 2$ 小行列を出力
11+
12+
計算量は $O(nm)$ や $O(n^2)$ なので,ジャッジへの提出にこの関数の実行を含めると TLE となりうるので注意.
13+
14+
## 使用方法
15+
16+
行列を `std::vector<std::vector<long long>>` 等の形で直接与えるのではなく, `int` 2 つを引数として重みを返す関数 `cost(int, int)` を引数として与えればよい.
17+
18+
### $n$ 頂点 DAG の辺重み関数の Monge 性判定
19+
20+
```cpp
21+
int n; // 頂点: 0, 1, ..., (n - 1)
22+
using T = long long;
23+
T INF;
24+
auto cost = [&](int i, int j) -> T {
25+
// Return weight of directed edge i->j, or INF if the edge does not exist.
26+
};
27+
28+
cerr << check_dag_monge(cost, INF, n) << endl;
29+
```
30+
31+
## Monge 性の確認方法
32+
33+
隣接する 2 行と 2 列の要素からなる全ての $2 \times 2$ 小行列に対する Monge 性を確認すればよい [1]
34+
35+
## Links
36+
37+
- [1] [[Monge まとめ①] Monge 性とは? - HackMD](https://hackmd.io/@tatyam-prime/monge1)

other_algorithms/monge_shortest_path.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Cost ret = monge_shortest_path_with_specified_edges(n, l, r, max_weight, f);
4040
- [AtCoder Beginner Contest 218 H - Red and Blue Lamps](https://atcoder.jp/contests/abc218/tasks/abc218_h)
4141
- [東京海上日動プログラミングコンテスト2024(AtCoder Beginner Contest 355) G - Baseball](https://atcoder.jp/contests/abc355/tasks/abc355_g)
4242
- [東北大学プログラミングコンテスト 2022 K - Lebesgue Integral](https://atcoder.jp/contests/tupc2022/tasks/tupc2022_k)
43+
- [Educational Codeforces Round 181 (Rated for Div. 2) F. Timofey and Docker](https://codeforces.com/contest/2125/problem/F)
4344

4445
## Links
4546

0 commit comments

Comments
 (0)