Typical DP Contest - H ナップザック
H: ナップザック - Typical DP Contest | AtCoder
// // * 普通に考えると dp[used_color_sum][weight_sum] を更新する。 // => どの色を使ったのかの判定はどうする? // => 色ごとに DP を更新していけばよい。 // class h_knapsack { public: void solve(void) { int N,W,C; cin>>N>>W>>C; map<int,vector<pair<int,int>>> items; REP(i, N) { int w,v,c; cin>>w>>v>>c; // 色ごとに振り分ける items[c].emplace_back(w,v); } // dp[今まで使った色の合計][重さの合計] vector<vector<int>> dp(C+1, vector<int>(W+1, 0)); // 色ごとに更新する for (const auto &pp : items) { const auto &citems = pp.second; // 現在の色の品物を必ず使う DP vector<vector<int>> dp2(dp); for (int i = 0; i < citems.size(); ++i) { int w, v; tie(w, v) = citems[i]; for (int c_sum = C; c_sum >= 0; --c_sum) for (int w_sum = W; w_sum >= w; --w_sum) { // dp2[i+1][c_sum][w_sum+w] = max(. , dp2[i][c_sum][w_sum]+v) // i が 1 刻みなので同じ配列を使いまわす dp2[c_sum][w_sum] = max(dp2[c_sum][w_sum], dp2[c_sum][w_sum-w]+v); } } // 前回の結果にマージ REP(c_sum, C+1) REP(w_sum, W+1) { if (c_sum+1 <= C) // dp2[c_sum][] は c_sum に現在の色を追加したものなので c_sum+1 と比較 dp[c_sum+1][w_sum] = max(dp[c_sum+1][w_sum], dp2[c_sum][w_sum]); } } int ans = 0; REP(c_sum, C+1) REP(w_sum, W+1) ans = max(ans, dp[c_sum][w_sum]); cout<<ans<<endl; } };