EOJ 2799 区间覆盖
在网上搜索这个题目,几乎全是那个用贪心做的版本……
这题用的是 dp。重点在降复杂度的思维上:用一个 w[i][j] 数组记录完全覆盖区间 i..=j 的最小花销。不过这个定义是不严谨的,因为如果 w[1][3] != kInf 并且 w[4][5] != kInf,w[1][5] 还是可能等于 kInf。但是看按步 dp 的时候这个小问题对正确性没有影响。
详细的解释在代码注释里啦。
#include "bits/stdc++.h"
using namespace std;
using u32 = uint32_t;
using u64 = uint64_t;
/******************************************************************************/
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
u32 t;
cin >> t;
for (u32 _ = 0; _ != t; ++_) {
cout << "case #" << _ << ":\n";
u32 n, m, k;
cin >> n >> m >> k;
u64 constexpr static kMaxWeight = 1000000000;
u64 constexpr static kInf = numeric_limits<u64>::max() / 2 - kMaxWeight;
vector<vector<u64>> w(n + 1, vector<u64>(n + 1, kInf));
vector<vector<u64>> dp(n + 1, vector<u64>(n + 1, kInf));
for (auto& i : dp) {
i[0] = 0;
}
for (u32 i = 0; i != m; ++i) {
u32 l, r, cost;
cin >> l >> r >> cost;
for (u32 j = l, j_end = r + 1; j != j_end; ++j) {
if (w[j][r] > cost) {
w[j][r] = cost;
}
}
}
for (u32 i = 1, i_end = n + 1; i != i_end; ++i) {
for (u32 j = 1; j != i; ++j) {
dp[i][j] = dp[i - 1][j];
for (u32 u = 1, u_end = j + 1; u != u_end; ++u) {
auto tmp = dp[i - u][j - u] + w[i - u + 1][i];
if (dp[i][j] > tmp) {
dp[i][j] = tmp;
}
}
}
}
// find the answer, since the question asks for the `at least` condition
// CAVEAT: Dereferencing `.end()` may cause runtime error in VS debug mode.
// If so, try `&dp[n].back() + 1`.
auto ans = *min_element(&dp[n][k], &*dp[n].end());
if (ans == kInf) {
cout << "-1\n";
} else {
cout << ans << '\n';
}
}
}

浙公网安备 33010602011771号