yukicoder No.324 - 落ちてた閉路グラフ
解法
動的計画法です.
:=(番目の頂点まで見ていて, 選んだ頂点の数が, 直前の頂点を選んだかどうかが, 最初の頂点を選んだかどうかが, このときのコストの最大値)とします.
これを用いて番目までの頂点まで見た後, とがともに真であるような状態については, の辺のコストを加えることになります. このように最後の補正を行った後に, 計算した値より最大コストを求めればよいです.
ソースコード
#include <iostream> using namespace std; const int kNEG_INF = -(1 << 28); const int kMAX_N = 3010; const int kMAX_M = 3010; int n, m; int w[kMAX_N]; int dp[2][kMAX_M][2][2]; // dp[i+1][v_num][pre_used][top_used] void Initialize(int arr[][2][2]) { for (int i = 0; i <= m; i++) for (int j = 0; j <= 1; j++) for (int k = 0; k <= 1; k++) arr[i][j][k] = kNEG_INF; } void Solve() { // dp Initialize(dp[0]); dp[0][0][0][0] = 0; for (int v_i = 0; v_i < n; v_i++) { Initialize(dp[(v_i + 1) % 2]); for (int v_num = 0; v_num <= m; v_num++) { for (int pre_used = 0; pre_used <= 1; pre_used++) { for (int top_used = 0; top_used <= 1; top_used++) { if (dp[v_i % 2][v_num][pre_used][top_used] <= kNEG_INF) continue; // 使わない dp[(v_i + 1) % 2][v_num][false][top_used] = max(dp[(v_i + 1) % 2][v_num][false][top_used], dp[v_i % 2][v_num][pre_used][top_used]); if (v_num + 1 > m) continue; // 使う if (pre_used) { // 辺のコストが追加 dp[(v_i + 1) % 2][v_num + 1][true][top_used | (v_i == 0)] = max(dp[(v_i + 1) % 2][v_num + 1][true][top_used | (v_i == 0)], dp[v_i % 2][v_num][pre_used][top_used] + w[(v_i - 1 + n) % n]); } else { // 辺のコストは増えない dp[(v_i + 1) % 2][v_num + 1][true][top_used | (v_i == 0)] = max(dp[(v_i + 1) % 2][v_num + 1][true][top_used | (v_i == 0)], dp[v_i % 2][v_num][pre_used][top_used]); } } } } } int ans = kNEG_INF; for (int pre_used = 0; pre_used <= 1; pre_used++) { for (int top_used = 0; top_used <= 1; top_used++) { ans = max(ans, dp[n % 2][m][pre_used][top_used] + (pre_used && top_used ? w[n - 1] : 0)); } } cout << ans << endl; } int main() { cin >> n >> m; for (int i = 0; i < n; i++) { cin >> w[i]; } Solve(); return 0; }
感想
ちょうどいい難易度でした.