今回は趣向を変えてみてナップザック問題をC++と動的計画法で解いてみます
ナップザック問題については以下のサイトが参考になるかと思います
-
ナップサック問題を動的計画法で解く - 具体例で学ぶ数学
ナップサック問題の問題設定と、動的計画法(表を順々に埋めていく方法)による解き方を解説します。 ナップサック問
続きを読む
0-1ナップザック問題(アイテムを1つだけ選べる場合)
とりあえず先にコードを起こしてみます
// アイテムを表す構造体
struct Item {
int value; // アイテムの価値
int weight; // アイテムの重さ
};
int Knapsack01(std::vector<Item>& items, int capacity)
{
// アイテムの数
int n = items.size();
// 動的計画法で使用するテーブル
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(capacity + 1));
// テーブルを埋めていく
for (int i = 0; i <= n; i++) {
for (int w = 0; w <= capacity; w++) {
if (i == 0 || w == 0) {
dp[i][w] = 0; // 初期条件
} else if (items[i - 1].weight <= w) {
// i番目のアイテムを選ぶ場合と選ばない場合で、価値が大きい方を選ぶ
dp[i][w] = std::max(items[i - 1].value + dp[i - 1][w - items[i - 1].weight], dp[i - 1][w]);
} else {
// i番目のアイテムは選べないので、i-1番目までのアイテムで価値を最大化
dp[i][w] = dp[i - 1][w];
}
}
}
// ナップザックの最大価値を返す
return dp[n][capacity];
}
int main() {
std::vector<Item> items = { {10, 60}, {20, 100}, {30, 120} }; // アイテムの重さと価値
int capacity = 50; // ナップザックの容量
int max_value = Knapsack01(items, capacity);
std::cout << "得られる最大値(Knapsack01): " << max_value << std::endl;
}
dp[i][w]は「最初のi個のアイテムの中からいくつか選んで、その重さの合計がw以下になるようにするときの、価値の合計の最大値」を表しています。ループの中で、i番目のアイテムをナップザックに入れるかどうかを決めます。
dp[i][w] = dp[i - 1][w]では現在のアイテムを入れるとナップザックの容量を超えてしまうので、そのアイテムは入れません。
dp[i][w] = std::max(items[i - 1].value + dp[i - 1][w - items[i - 1].weight], dp[i - 1][w])では、そのアイテムを入れるか入れないか、価値の合計が大きくなる方を選びます。
最終的にdp[n][capacity]には、全てのアイテムからいくつか選んでナップザックの容量capacityを超えないようにしたときの、価値の合計の最大値を格納しています
無制限ナップサック問題(各アイテムを何度でも選ぶことができる場合)
続いて、同じナップザック問題ですが少し勝手がかわるものになります
int UnboundedKnapsack(std::vector<Item>& items, int capacity) {
int n = items.size();
// 動的計画法で使用するテーブル
std::vector<int> dp(capacity + 1, 0);
// テーブルを埋めていく
for (int w = 0; w <= capacity; w++) {
for (int i = 0; i < n; i++) {
if (items[i].weight <= w) {
// i番目のアイテムを選ぶ場合と選ばない場合で、価値が大きい方を選ぶ
dp[w] = std::max(dp[w], items[i].value + dp[w - items[i].weight]);
}
}
}
// ナップザックの最大価値を返す
return dp[capacity];
}
int main() {
std::vector<Item> items = { {2, 40}, {3, 50}, {5, 70} };
int capacity = 4;
int max_value = UnboundedKnapsack(items, capacity);
std::cout << "得られる最大値(UnboundedKnapsack): " << max_value << std::endl;
}
こちらも0-1ナップザック問題とあまり変わらずに実装できました
最後に
今回はいつもと趣向の違った内容で記事にしてみましたが、こういうアルゴリズム的なものに挑戦するのも楽しいですね
会社紹介
私が所属しているアドバンスド・ソリューション株式会社(以下、ADS)は一緒に働く仲間を募集しています
会社概要
「技術」×「知恵」=顧客課題の解決・新しい価値の創造
この方程式の実現はADSが大切にしている考えで、技術を磨き続けるgeekさと、顧客を思うloveがあってこそ実現できる世界観だと思っています
この『love & geek』の精神さえあれば、得意不得意はno problem!
技術はピカイチだけど顧客折衝はちょっと苦手。OKです。技術はまだ未熟だけど顧客と知恵を出し合って要件定義するのは大好き。OKです
凸凹な社員の集まり、色んなカラーや柄の個性が集まっているからこそ、常に新しいソリューションが生まれています
ミッション
私たちは、テクノロジーを活用し、業務や事業の生産性向上と企業進化を支援します
-
アドバンスド・ソリューション株式会社
アドバンスド・ソリューションは主にMicrosoft製品を使用して、企業の生産性向上に取り組んでいます。要件定義から導入 ...
サイトへ移動
-
お問い合わせ | アドバンスド・ソリューション株式会社
お問い合わせはこちら