1.基本的な問題
N項目Vとバックパックの容量があります。最初に\(I \)のスペースを消費アイテム(C_I \)\、結果の値は、(W_i \)\。和の最大値を可能にするバックパックにアイテムを解きます。
1.1アイデア
各アイテムは一つだけで、あなたが選択するか、省略することができます。これは、によって特徴付けられる最も基本的なナップザック問題、です。サブ問題は状態によって定義される:すなわち\(F [I、V] \) だけバックパック利用可能な最大容量値vに入れ私の項目の前に示します。これは、状態遷移式である:
\(F. [I、V] = maxの\ {F. [1-I、V。]、F. + W_i \ [1-I、V-C_I。]} \)
1.2コアコード
memset(F[0], 0, sizeof(F[0]));
for (int i = 1; i <= n; ++i) {
for (int v = 0; v <= V; ++v) {
if (v >= c[i]) F[i][v] = max(F[i-1][v], F[i-1][v-c[i]] + w[i]);
else F[i][v] = F[i-1][v];
}
}
for (int i = 0; i <= V; ++i) ans = max(ans, F[n][i]);
時間の複雑さと空間の複雑されている\(O(NV)\) 、時間複雑さが実質的に最適化されたが、空間的複雑さ、それだけに最適化することができることができない、請求\(O(V)\) 。
memset(F, 0, sizeof(F));
for (int i = 1; i <= n; ++i) {
for (int v = V; v >= c[i]; --v) {
F[v] = max(F[v], F[v-c[i]] + w[i]);
}
}
for (int i = 0; i <= V; ++i) ans = max(ans, F[i]);
2.プログラムの数を求めて
:質問を見て、小さなアラカルト・
質問はこのような変更を求められ、一般的な単純に状態遷移方程式\(最大\)に\(合計が\)することができます。各項目がある場合、例えば、完全にバックパック物品移載方程式である
\(F [I、V] =合計\ {F [I-1、V]、F [I、V-C_I] \} \)
初期条件は、\(F. [0,0] = 1 \) 。
F[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int v = 0; v <= V; ++v) {
if (v >= c[i]) F[i][v] = F[i-1][v] + F[i-1][v-c[i]];
else F[i][v] = F[i-1][v];
}
}
ans = F[n][V];
printf("%d\n", ans);
フル追求するふりをしてみてください3.
:質問を見て梱包問題[質問4のNOIp2001普遍セット]
ここでは、実際には(W_i \)\です\(C_I \) 。
memset(F, 0, sizeof(F));
for (int i = 1; i <= n; ++i) {
for (int v = V; v >= c[i]; --v) {
F[v] = max(F[v], F[v-c[i]] + c[i]);
}
}
for (int i = 0; i <= V; ++i) ans = max(ans, F[i]);
printf("%d\n", V - ans);
4.すべての可能なの音量が求め
:質問来た建物城は
、それぞれの城の高さの数を算出しました。
for (int i = 0; i < n; ++i) {
int np = 0;
int now;
int sum = 0;
while (1) {
scanf("%d", &now);
if (now == -1) break;
a[++np] = now;
sum += now;
}
if (max_sum < sum) max_sum = sum;
memset(F, 0, sizeof(F));
F[0] = 1;
for (int j = 1; j <= np; ++j) {
for (int v = sum; v >= a[j]; --v) {
if (F[v-a[j]] && !F[v]) {
++h[v];
F[v] = 1;
}
}
}
}