結果
| 問題 |
No.2869 yuusaan's Knapsacks
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-08-31 09:27:54 |
| 言語 | D (dmd 2.109.1) |
| 結果 |
AC
|
| 実行時間 | 1,171 ms / 4,500 ms |
| コード長 | 2,467 bytes |
| コンパイル時間 | 5,508 ms |
| コンパイル使用メモリ | 176,836 KB |
| 実行使用メモリ | 18,160 KB |
| 最終ジャッジ日時 | 2024-08-31 09:28:11 |
| 合計ジャッジ時間 | 16,267 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 27 |
ソースコード
import std;
void main () {
int N, M; readln.read(N, M);
auto e = readln.split.to!(int[]);
auto v = new int[](M);
auto w = new int[](M);
foreach (i; 0..M) {
readln.read(v[i], w[i]);
}
// 複数のナップサックに適切な部分集合を割り当てていく -> 例のO(3^M)チャンス
auto cost = new long[](1 << M);
auto value = new long[](1 << M);
foreach (S; 0..(1 << M)) {
long co = 0, va = 0;
foreach (i; 0..M) if (0 < (S & (1 << i))) {
co += w[i];
va += v[i];
}
cost[S] = co;
value[S] = va;
}
auto dp = new long[][](N + 1, 1 << M);
// dp[i][S] := 最初のi個のナップサックに割り当てる部分集合を確定させて、未使用アイテムがSの状態における最大価値
auto prev = new int[][](N + 1, 1 << M);
foreach (p; prev) p[] = -1;
foreach (d; dp) d[] = -long.max;
dp[0][(1 << M) - 1] = 0;
foreach (i; 0..N) {
foreach (S; 0..(1 << M)) {
if (dp[i][S] == -long.max) continue;
// 非空部分集合の列挙
for (uint sub = S; 0 < sub; sub = (sub - 1) & S) {
if (cost[sub] <= e[i]) {
if (dp[i + 1][S ^ sub] < dp[i][S] + value[sub]) {
dp[i + 1][S ^ sub] = dp[i][S] + value[sub];
prev[i + 1][S ^ sub] = sub;
}
}
}
// 取らない
if (dp[i + 1][S] < dp[i][S]) {
dp[i + 1][S] = dp[i][S];
prev[i + 1][S] = 0;
}
}
}
long ans = 0;
foreach (d; dp[N]) ans = max(ans, d);
writeln(ans);
// 復元
auto took = new int[](0);
int cur = N;
int set = () {
foreach (S; 0..(1 << M)) if (dp[N][S] == ans) {
return S;
}
assert(0);
}();
while (0 < cur) {
took ~= prev[cur][set];
set |= prev[cur][set];
cur--;
}
took.reverse;
foreach (t; took) {
import core.bitop : popcnt;
write(popcnt(t));
foreach (i; 0..M) if (0 < (t & (1 << i))) {
write(" ", i + 1);
}
write("\n");
}
}
void read (T...) (string S, ref T args) {
import std.conv : to;
import std.array : split;
auto buf = S.split;
foreach (i, ref arg; args) {
arg = buf[i].to!(typeof(arg));
}
}