バレンタインデー、みなさんいかがお過ごしでしょうか。私はいつもと変わらず競プロをやっています。というわけで今回は ABC018 D 問題です。
問題概要
原文 → D: バレンタインデー - AtCoder Beginner Contest 018 | AtCoder
女子が 人、男子が
人いる中から、女子
人、男子
人からなるグループを作る。
チョコレートは 個あり、番号が
である女子は番号が
である男子に幸福度
である
番目のチョコレートを渡すが、これは番号が
である女子と番号が
である男子が両方ともグループに含まれている時に限り渡すことができる。
渡されたチョコレートの幸福度の合計値の最大値を出力せよ。
解説
女子の組み合わせ、ならびに男子の組み合わせを総当りで考えてしまうと、組み合わせが 通りあるため間に合わず、この問題の制約では部分点止まりになります。
満点解法では、「グループに入れる女子を固定すれば、チョコレートを貰う男子とその男子が得る幸福度がわかる」ことに着目します。グループにどの男子を入れるかについては、幸福度が大きい男子から貪欲に選択するのが最適です。いわゆる半分全列挙というやつです。したがって、次の流れで実装すればよいです。
- グループに女子を
人入れる各組み合わせについて以下を行う
- チョコをもらう可能性のある男子について、幸福度を計算する
- 幸福度が大きい順に男子を
人選び、その男子の幸福度の合計を計算し、その max を答えとする
この方針で解くと男子の組み合わせを列挙する必要がなくなるため、間に合います。
ソースコード
signed main() { int n, m, p, q, r; cin >> n >> m >> p >> q >> r; vector<pii> v[20]; rep(i,0,r) { int x, y, z; cin >> x >> y >> z; x--; y--; v[x].pb(pii(y,z)); } int ans = 0; rep(i,0,(1 << n)) { int bcnt = __builtin_popcount(i); if(bcnt != p) continue; int value[20] = {}; rep(j,0,n) { if(i >> j & 1) { rep(k,0,v[j].size()) { int to = v[j][k].fr; int cost = v[j][k].sc; value[to] += cost; } } } sort(value, value + m, greater<int>()); int temp = 0; rep(j,0,q) temp += value[j]; ans = max(ans, temp); } cout << ans << endl; return 0; }
余談
2/9 の SRM 708 で、念願の Div1 昇格を果たしました。初めて青になれたのでうれしかったです。
Div1?わーい!すごーい! pic.twitter.com/WGN97oGH6M
— つたじろう (ABC-D 24/43) (@_TTJR_) 2017年2月9日
2017/02/09 TopCoder SRM 708 Div.2
— つたじろう (ABC-D 24/43) (@_TTJR_) 2017年2月9日
1173 -> 1202
初昇格。やらかすと即刻緑落ちするスリリングな世界 #tsutajmemo
青底辺から上がれるようにこれからも頑張ります。