ナップサック問題
■ダイナミックプログラミング(動的計画法)とは
最適化問題を解くのに効果的な方法。
具体的には、n個の要素に関する問題の最適解を求めるのに、部分集合であるi個の問題の最適解を覚えておき、
i個から1つ要素を増やした場合、覚えておいた最適解が変化するを調べる。
変化した場合は、それを最適解とし、最終的にn個の問題の最適解を見つけることができるというものだ。
■ナップサック問題
ダイナミックプログラミングの代表的な例題。
入れることのできる重さが決まっているナップサックに、どれだけ無駄がなく詰めきれるかというもの。
今回は、重さと値段があるデータについて、なるべくナップサックの中身が高価格になるようにつめる
という問題に取り組むことにした。
下記がソースです。 ただ、ちょっと今日は忙しかったんで書きなぐった状態です。
気が向いたら、きれいに書きなおそうと思います。
#include <stdio.h> #include <memory.h> // 適当にナップサックに入れる商品リストを定義する struct Goods { int no; char name[80]; int weight; int price; }goods[] = { {0 ,"Wii" ,4 , 4500}, {1 ,"XBOX360" ,5 , 6100}, {2 ,"PSP" ,2 , 2100}, {3 ,"DS" ,1 , 1000}, {4 ,"PS3" ,6 , 5050} }; void main() { const int KNAP_SIZE_MAX = 8; // ナップサックに入る最大重量 int item[KNAP_SIZE_MAX+1] = {0}; int value[KNAP_SIZE_MAX+1] = {0}; for( int j=0; j<sizeof(goods)/sizeof(Goods); j++ ){ // 商品分のループ for( int i=1; i<=KNAP_SIZE_MAX; i++ ){ // ナップサックサイズのループ int knapSpace = i - goods[j].weight; if( knapSpace >=0 && knapSpace <= KNAP_SIZE_MAX ){ int newValue = value[knapSpace] + goods[j].price; if( newValue > value[i] ){ value[i] = newValue; item[i] = goods[j].no; } } } } // 結果表示 for( int i=1; i <= KNAP_SIZE_MAX; i++ ){ printf( "%4d,", value[i] ); } printf("\n"); for( int i=1; i <= KNAP_SIZE_MAX; i++ ){ printf( "%4d,", item[i] ); } printf("\n"); printf("ナップサックに入れるもの\n"); int count = 0; int inItem[KNAP_SIZE_MAX]; // ナップサックに入れる最適な商品 memset( inItem, -1, sizeof(inItem) ); int nokori = KNAP_SIZE_MAX; // ナップサックの残りサイズ do{ int inItem_ = nokori; nokori = nokori - goods[ item[nokori] ].weight; inItem[count++] = item[inItem_]; }while( nokori != 0 ); for( int i=0; i < KNAP_SIZE_MAX; i++ ){ if( inItem[i] > -1 ){ printf( "%d:%s, ", inItem[i], goods[ inItem[i] ].name ); } } printf("\n"); }
出力
1000,2100,3100,4500,6100,7100,8200,9200, 3, 2, 3, 0, 1, 3, 2, 3, ナップサックに入れるもの 3:DS, 2:PSP, 1:XBOX360,
最終的な最適化表と、求めた買ったナップサックに入れるものです。
DS, PSP, XBOX360 をナップサックに詰めた場合、今回は一番高価になるようです。