Skip to content

Commit fc0371c

Browse files
authored
enumerate-maximum-independent-set-path-sums に最小値を実装 (#102)
* enumerate-maximum-independent-set-path-sums に最小値を実装 * 区切りの改行を `,` に変更
1 parent e0c4c80 commit fc0371c

3 files changed

Lines changed: 135 additions & 42 deletions

docs/other/enumerate-maximum-independent-set-path-sums.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
---
2-
title: 列の隣り合わない $k$ 個の要素を選んだ総和の最大値の列挙
2+
title: 列の隣り合わない $k$ 個の要素を選んだ総和の最大値または最小値の列挙
33
documentation_of: other/enumerate-maximum-independent-set-path-sums.hpp
44
---
55

66
## 概要
77

8-
長さ $n$ の列 $a$ について、隣り合わない $k$ 個の添字を選んだときの $a_i$ の総和の最大値を、全ての $k$ に対して列挙する。
8+
長さ $n$ の列 $a$ について、隣り合わない $k$ 個の添字を選んだときの $a_i$ の総和の最大値または最小値を、全ての $k$ に対して列挙する。
99

10-
- パス上の最大重み独立集合について、独立集合の大きさごとの最大重みを求めるものとみなせる
10+
- パス上の重み付き独立集合について、独立集合の大きさごとの最大重みまたは最小重みを求めるものとみなせる
1111
- 返り値の長さは $\lceil n / 2 \rceil + 1$ である。
12-
- 返り値の $k$ 番目 (0-based indexing) の要素は、 $k$ 個選んだときの総和の最大値である
12+
- 返り値の $k$ 番目 (0-based indexing) の要素は、`maximum``true` であれば $k$ 個選んだときの総和の最大値、`false` であれば $k$ 個選んだときの総和の最小値である
1313

1414
## 使い方
1515

16-
`enumerate_maximum_independent_set_path_sums(a)`
16+
`enumerate_maximum_independent_set_path_sums<T, bool maximum = true>(a)`, `enumerate_maximum_independent_set_path_sums<bool maximum, T>(a)`
1717

1818
- 比較ソートを用いる。
1919
- 引数 $a$ は重みの列である。
20-
- 返り値は、$k$ 個選ぶときの最大値を $k$ 番目 (0-based indexing) の要素に持つ列である。
20+
- `maximum` は既定で `true` であり、`true` であれば最大値、`false` であれば最小値を返す。
21+
- 返り値は、$k$ 個選ぶときの最大値または最小値を $k$ 番目 (0-based indexing) の要素に持つ列である。
2122
- 前提: `T` は加算、減算、比較が正しく定義されている。
2223
- 前提: アルゴリズム中に現れる加減算結果、および返り値の各要素が `T` の範囲に収まる。
2324
- 前提: `std::is_unsigned_v<T>``false` である。
2425

25-
`enumerate_maximum_independent_set_path_sums_bucket_sort(a)`
26+
`enumerate_maximum_independent_set_path_sums_bucket_sort<T, bool maximum = true>(a)`, `enumerate_maximum_independent_set_path_sums_bucket_sort<bool maximum, T>(a)`
2627

2728
- バケットソートを用いる。
2829
- 引数 $a$ は重みの列である。
29-
- 返り値は、$k$ 個選ぶときの最大値を $k$ 番目 (0-based indexing) の要素に持つ列である。
30+
- `maximum` は既定で `true` であり、`true` であれば最大値、`false` であれば最小値を返す。
31+
- 返り値は、$k$ 個選ぶときの最大値または最小値を $k$ 番目 (0-based indexing) の要素に持つ列である。
3032
- 前提: `T``bool` でない 32 bit 以下のプリミティブな符号付き整数型である。
3133
- 前提: `std::is_unsigned_v<T>``false` である。
3234
- 前提: 引数として与えられる列は非負整数列である。

other/enumerate-maximum-independent-set-path-sums.hpp

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#ifndef OTHER_ENUMERATE_MAXIMUM_INDEPENDENT_SET_PATH_SUMS_HPP
22
#define OTHER_ENUMERATE_MAXIMUM_INDEPENDENT_SET_PATH_SUMS_HPP
33

4-
// 長さ n の列から隣り合わない k 個を選ぶ総和の最大値を全ての k について求める。
4+
// 長さ n の列から隣り合わない k 個を選ぶ総和の最大値または最小値を全ての k について求める。
55
// 符号なし整数型は使用できない。
6-
// 比較ソートによる実装は O(n log n)、
7-
// バケットソートによる実装は非負整数列の総和を S として O(n + S)。
6+
// 比較ソートによる実装は O(n log n)、バケットソートによる実装は非負整数列の総和を S として O(n + S)。
87

98
#include <algorithm>
109
#include <cassert>
@@ -16,18 +15,24 @@
1615
#include <vector>
1716

1817
namespace enumerate_maximum_independent_set_path_sums_internal {
19-
template <class T>
20-
bool leq(const std::pair<bool, T> &x, const std::pair<bool, T> &y) {
21-
if (!x.first) {
18+
template <bool maximum, class T>
19+
bool removable_side(const std::pair<bool, T> &side,
20+
const std::pair<bool, T> &center) {
21+
if (!side.first) {
2222
return true;
2323
}
24-
if (!y.first) {
24+
if (!center.first) {
2525
return false;
2626
}
27-
return !(y.second < x.second);
27+
if constexpr (maximum) {
28+
return !(center.second < side.second);
29+
} else {
30+
return !(side.second < center.second);
31+
}
2832
}
2933

30-
template <class T> std::vector<T> marginal_values(const std::vector<T> &a) {
34+
template <class T, bool maximum>
35+
std::vector<T> marginal_values(const std::vector<T> &a) {
3136
using P = std::pair<bool, T>;
3237
const P none(false, T());
3338
std::vector<P> stack;
@@ -38,8 +43,8 @@ template <class T> std::vector<T> marginal_values(const std::vector<T> &a) {
3843

3944
const auto add = [&](P x) {
4045
while (stack.size() >= 2 && stack.back().first &&
41-
leq(x, stack.back()) &&
42-
leq(stack[stack.size() - 2], stack.back())) {
46+
removable_side<maximum>(x, stack.back()) &&
47+
removable_side<maximum>(stack[stack.size() - 2], stack.back())) {
4348
const P l = stack[stack.size() - 2];
4449
const P p = stack.back();
4550
res.push_back(p.second);
@@ -69,19 +74,23 @@ template <class T> std::size_t bucket_index(const T x, const T offset) {
6974
}
7075
} // namespace enumerate_maximum_independent_set_path_sums_internal
7176

72-
template <class T>
77+
template <class T, bool maximum = true>
7378
std::vector<T>
7479
enumerate_maximum_independent_set_path_sums(const std::vector<T> &a) {
7580
static_assert(!std::is_unsigned_v<T>,
7681
"T must not be an unsigned type in "
7782
"enumerate_maximum_independent_set_path_sums.");
7883

7984
std::vector<T> xs =
80-
enumerate_maximum_independent_set_path_sums_internal::marginal_values(
81-
a);
82-
std::sort(xs.begin(), xs.end(),
83-
[](const T &x, const T &y) { return y < x; });
84-
85+
enumerate_maximum_independent_set_path_sums_internal::marginal_values<
86+
T, maximum>(a);
87+
std::sort(xs.begin(), xs.end(), [](const T &x, const T &y) {
88+
if constexpr (maximum) {
89+
return y < x;
90+
} else {
91+
return x < y;
92+
}
93+
});
8594
std::vector<T> res(1, T());
8695
res.reserve(xs.size() + 1);
8796
T sum = T();
@@ -92,7 +101,13 @@ enumerate_maximum_independent_set_path_sums(const std::vector<T> &a) {
92101
return res;
93102
}
94103

95-
template <class T>
104+
template <bool maximum, class T>
105+
std::vector<T>
106+
enumerate_maximum_independent_set_path_sums(const std::vector<T> &a) {
107+
return enumerate_maximum_independent_set_path_sums<T, maximum>(a);
108+
}
109+
110+
template <class T, bool maximum = true>
96111
std::vector<T> enumerate_maximum_independent_set_path_sums_bucket_sort(
97112
const std::vector<T> &a) {
98113
static_assert(!std::is_unsigned_v<T>,
@@ -112,8 +127,8 @@ std::vector<T> enumerate_maximum_independent_set_path_sums_bucket_sort(
112127
}
113128

114129
const std::vector<T> xs =
115-
enumerate_maximum_independent_set_path_sums_internal::marginal_values(
116-
a);
130+
enumerate_maximum_independent_set_path_sums_internal::marginal_values<
131+
T, maximum>(a);
117132
const std::size_t offset = static_cast<std::size_t>(total);
118133
assert(offset <= (std::numeric_limits<std::size_t>::max() - 1) / 2);
119134
std::vector<std::size_t> count(offset * 2 + 1, 0);
@@ -125,19 +140,41 @@ std::vector<T> enumerate_maximum_independent_set_path_sums_bucket_sort(
125140
std::vector<T> res(1, T());
126141
res.reserve(xs.size() + 1);
127142
T sum = T();
128-
for (T x = total;; x -= T(1)) {
129-
const std::size_t c =
130-
count[enumerate_maximum_independent_set_path_sums_internal::
131-
bucket_index(x, total)];
132-
for (std::size_t i = 0; i < c; i += 1) {
133-
sum += x;
134-
res.push_back(sum);
143+
if constexpr (maximum) {
144+
for (T x = total;; x -= T(1)) {
145+
const std::size_t c =
146+
count[enumerate_maximum_independent_set_path_sums_internal::
147+
bucket_index(x, total)];
148+
for (std::size_t i = 0; i < c; i += 1) {
149+
sum += x;
150+
res.push_back(sum);
151+
}
152+
if (x == -total) {
153+
break;
154+
}
135155
}
136-
if (x == -total) {
137-
break;
156+
} else {
157+
for (T x = -total;; x += T(1)) {
158+
const std::size_t c =
159+
count[enumerate_maximum_independent_set_path_sums_internal::
160+
bucket_index(x, total)];
161+
for (std::size_t i = 0; i < c; i += 1) {
162+
sum += x;
163+
res.push_back(sum);
164+
}
165+
if (x == total) {
166+
break;
167+
}
138168
}
139169
}
140170
return res;
141171
}
142172

173+
template <bool maximum, class T>
174+
std::vector<T> enumerate_maximum_independent_set_path_sums_bucket_sort(
175+
const std::vector<T> &a) {
176+
return enumerate_maximum_independent_set_path_sums_bucket_sort<T, maximum>(
177+
a);
178+
}
179+
143180
#endif

verify/standalone-enumerate-maximum-independent-set-path-sums.test.cpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
#include "../other/enumerate-maximum-independent-set-path-sums.hpp"
1010

11-
template <class T> std::vector<T> brute_force(const std::vector<T> &a) {
11+
template <class T, bool maximum = true>
12+
std::vector<T> brute_force(const std::vector<T> &a) {
1213
const std::size_t n = a.size();
1314
const std::size_t m = (n + 1) / 2;
1415
std::vector<T> answer(m + 1, T());
@@ -28,9 +29,19 @@ template <class T> std::vector<T> brute_force(const std::vector<T> &a) {
2829
sum += a[i];
2930
}
3031
}
31-
if (ok && (!found[count] || answer[count] < sum)) {
32+
if (ok && !found[count]) {
3233
answer[count] = sum;
3334
found[count] = true;
35+
} else if (ok) {
36+
if constexpr (maximum) {
37+
if (answer[count] < sum) {
38+
answer[count] = sum;
39+
}
40+
} else {
41+
if (sum < answer[count]) {
42+
answer[count] = sum;
43+
}
44+
}
3445
}
3546
}
3647
for (std::size_t i = 0; i <= m; i += 1) {
@@ -44,8 +55,16 @@ void test_signed_exhaustive() {
4455
std::vector<long long> a(n);
4556
auto dfs = [&](auto self, const std::size_t i) -> void {
4657
if (i == n) {
58+
const std::vector<long long> expected = brute_force(a);
59+
const std::vector<long long> expected_min =
60+
brute_force<long long, false>(a);
4761
assert(enumerate_maximum_independent_set_path_sums(a) ==
48-
brute_force(a));
62+
expected);
63+
assert((enumerate_maximum_independent_set_path_sums<long long,
64+
false>(a) ==
65+
expected_min));
66+
assert(enumerate_maximum_independent_set_path_sums<false>(a) ==
67+
expected_min);
4968
return;
5069
}
5170
for (long long x = -3; x <= 3; x += 1) {
@@ -62,8 +81,14 @@ void test_small_signed_type_exhaustive() {
6281
std::vector<signed char> a(n);
6382
auto dfs = [&](auto self, const std::size_t i) -> void {
6483
if (i == n) {
84+
const std::vector<signed char> expected = brute_force(a);
85+
const std::vector<signed char> expected_min =
86+
brute_force<signed char, false>(a);
6587
assert(enumerate_maximum_independent_set_path_sums(a) ==
66-
brute_force(a));
88+
expected);
89+
assert((enumerate_maximum_independent_set_path_sums<signed char,
90+
false>(a) ==
91+
expected_min));
6792
return;
6893
}
6994
for (signed char x = -3; x <= 3;
@@ -81,8 +106,15 @@ void test_signed_bucket_sort() {
81106
std::vector<int> a(n);
82107
auto dfs = [&](auto self, const std::size_t i) -> void {
83108
if (i == n) {
109+
const std::vector<int> expected = brute_force(a);
110+
const std::vector<int> expected_min =
111+
brute_force<int, false>(a);
84112
assert(enumerate_maximum_independent_set_path_sums_bucket_sort(
85-
a) == brute_force(a));
113+
a) == expected);
114+
assert((enumerate_maximum_independent_set_path_sums_bucket_sort<
115+
int, false>(a) == expected_min));
116+
assert(enumerate_maximum_independent_set_path_sums_bucket_sort<
117+
false>(a) == expected_min);
86118
return;
87119
}
88120
for (int x = 0; x <= 4; x += 1) {
@@ -97,26 +129,44 @@ void test_signed_bucket_sort() {
97129
void test_bucket_large_values() {
98130
const std::vector<int> a = {100, 1, 100, 1, 100, 1, 100};
99131
const std::vector<int> expected = brute_force(a);
132+
const std::vector<int> expected_min = brute_force<int, false>(a);
100133
assert(enumerate_maximum_independent_set_path_sums(a) == expected);
134+
assert((enumerate_maximum_independent_set_path_sums<int, false>(a) ==
135+
expected_min));
101136
assert(enumerate_maximum_independent_set_path_sums_bucket_sort(a) ==
102137
expected);
138+
assert((enumerate_maximum_independent_set_path_sums_bucket_sort<int, false>(
139+
a) == expected_min));
103140

104141
const std::vector<std::int32_t> b = {3, 0, 5, 0, 4, 1};
105142
const std::vector<std::int32_t> expected_b = brute_force(b);
143+
const std::vector<std::int32_t> expected_b_min =
144+
brute_force<std::int32_t, false>(b);
106145
assert(enumerate_maximum_independent_set_path_sums_bucket_sort(b) ==
107146
expected_b);
147+
assert((enumerate_maximum_independent_set_path_sums_bucket_sort<
148+
std::int32_t, false>(b) == expected_b_min));
108149
}
109150

110151
void test_bucket_small_signed_types() {
111152
const std::vector<short> a = {2, 0, 3, 1, 4};
112153
const std::vector<short> expected = brute_force(a);
154+
const std::vector<short> expected_min = brute_force<short, false>(a);
113155
assert(enumerate_maximum_independent_set_path_sums_bucket_sort(a) ==
114156
expected);
157+
assert(
158+
(enumerate_maximum_independent_set_path_sums_bucket_sort<short, false>(
159+
a) == expected_min));
115160

116161
const std::vector<signed char> b = {2, 0, 3, 1, 4};
117162
const std::vector<signed char> expected_b = brute_force(b);
163+
const std::vector<signed char> expected_b_min =
164+
brute_force<signed char, false>(b);
118165
assert(enumerate_maximum_independent_set_path_sums_bucket_sort(b) ==
119166
expected_b);
167+
assert((enumerate_maximum_independent_set_path_sums_bucket_sort<signed char,
168+
false>(b) ==
169+
expected_b_min));
120170
}
121171

122172
struct TestNumber {
@@ -153,11 +203,15 @@ void test_custom_type() {
153203
TestNumber(1), TestNumber(4),
154204
TestNumber(5)};
155205
assert(enumerate_maximum_independent_set_path_sums(a) == brute_force(a));
206+
assert((enumerate_maximum_independent_set_path_sums<TestNumber, false>(a) ==
207+
brute_force<TestNumber, false>(a)));
156208
}
157209

158210
void test_floating_point() {
159211
const std::vector<double> a = {1.5, 100.25, 1.5, -3.0, 10.0, 2.0};
160212
assert(enumerate_maximum_independent_set_path_sums(a) == brute_force(a));
213+
assert((enumerate_maximum_independent_set_path_sums<double, false>(a) ==
214+
brute_force<double, false>(a)));
161215
}
162216

163217
void test_type_traits() {

0 commit comments

Comments
 (0)