C言語関係掲示板

過去ログ

No.1003 サンタさんの背負える袋の中身の価値を最大に

[戻る] [ホームページ]
No.924

アルゴリズム
投稿者---新米さん(2004/01/02 02:20:55)


クリスマスと言えばサンタクロース.サンタさんは背中に大きな袋を背負ってよい子の家を回り,クリスマスプレゼントを渡します.
最近のよい子はいろいろなプレゼントを欲しがるので,プレゼントの重さも価値もさまざまです.
サンタさんと言えども,袋に入れて背負うことのできる袋の重さには限界があります.でも,サンタさんは,その袋に詰めることのできる価値ができるだけ最大になるように,プレゼントを袋に入れたいと思っています.
さて,サンタさんが背負える重さ以内でプレゼントを袋に詰めるとき,その袋の中のプレゼントの価値を最大にするためにはどのような方法でプレゼントを選択すれば良いでしょうか.
サンタさんにとって悩ましいこの問題を解くアルゴリズムを考えてください.

アルゴリズムの入力:
n個のプレゼントp0,,p1,...,pn-1
プレゼントのそれぞれの重さw0,,w1,...,wn-1
プレゼントのそれぞれの価値v0,,v1,...,vn-1
サンタさんが背負うことのできる袋の最大の重さC
アルゴリズムの出力:
選択されたプレゼントの重さの和がCを越えないように,その価値の和を最大にするプレゼント {p0,,p1,...,pn-1} の部分集合

箇条書きの文章でそのアルゴリズムと示したアルゴリズムの計算時間量と得られる解の精度について教えてください。私にはさっぱり意味がわかりません。。。。

No.925

Re:アルゴリズム
投稿者---あかま(2004/01/02 05:39:28)


21になったらサンタさん来ませんでした。
入らなかったプレゼントでいいのでなんかください。

これは「ナップザック問題」というやつです。
検索すれば色々出てくるでしょう。で検索したらこんなのが出てきました。
http://www.geocities.co.jp/SiliconValley/5634/t82C8_0001.html
こんなこと言われちゃうと悲しいかな計算機屋はうなずいて弁当食べるしかできない。

で、問題にナップザックのナの字も出てないところに出題者の意図が見え隠れしている気がします。
>サンタさんにとって悩ましいこの問題を解くアルゴリズムを考えてください.
↑特にこの辺に。とりあえず調べるのは後回しにして自分で考えてほしかったんだと思うよ。

全件探索になると思うので、
計算量は2のn乗。
精度は100%最適値が見つかる。

枝刈をすれば計算量は減る。「上界値」あたりで検索するとよい。



No.926

Re:アルゴリズム
投稿者---あかま(2004/01/02 07:51:18)


アルゴリズムだけじゃC言語の勉強にならないのでザクっとプログラム

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int limit_weight,best_value,best_weight,jjj;
int Nnum,branch;
struct Item{
    int weight;
    int value;
}item[100];
int insert_num[100],best_ans_num[100];

int item_cmp(const void *a, const void *b){
    if(((struct Item *)a)->value/(double)((struct Item *)a)->weight >= ((struct Item *)b)->value/(double)((struct Item *)b)->weight)
        return -1;
    else return 1;
}

int get_bound(int deep,int weight,int value){//上界値の計算

    for(;deep < Nnum && limit_weight > weight + item[deep].weight;deep++){
        weight += item[deep].weight;
        value += item[deep].value;
    }
    return value + item[deep].value*(limit_weight-weight)/item[deep].weight;
}
void search(int deep,int weight,int value){
    branch++;
    if(deep < Nnum){
        /*この下3ヶ所のコメントを外すと枝刈できる*/
        //if(best_value < get_bound(deep,weight,value)){
            insert_num[deep] = 1;
        //  if(weight + item[deep].weight <= limit_weight) 
            search(deep+1,weight+item[deep].weight,value+item[deep].value);
            insert_num[deep] = 0;
            search(deep+1,weight,value);
        //}
    }
    else{
        if(limit_weight >= weight && value > best_value){
            best_value = value;
            best_weight = weight;
            memcpy(best_ans_num,insert_num,sizeof(int)*Nnum);
        }
    }
}
int main(){
    int i;
    scanf("%d",&limit_weight);
    for(Nnum=0;Nnum < 100 && scanf("%d %d",&item[Nnum].weight,&item[Nnum].value) != EOF;Nnum++);
    qsort(item,Nnum,sizeof(struct Item),item_cmp);

    search(0,0,0);
    
    printf("アイテム数%d\nナップザック容量 %d\n袋に入れるアイテム\n",Nnum,limit_weight);
    for(i = 0;i < Nnum;i++) if(best_ans_num[i]) printf("重量=%d 価値=%d\n",item[i].weight,item[i].value);
    printf("合計重量 %d\n合計価値 %d\n",best_weight,best_value);
    printf("分岐した枝の数 %d\n",branch);
    return 1;
}

プログラムはファイルからリダイレクトで読みこみ。最初に
ナップザック容量
次に
アイテム重量 アイテム価値
がアイテムの数続く
例↓容量50 アイテム10個

50
10 5
7 3
4 4
15 9
6 10
20 8
6 5
13 7
25 18
1 2

関係ないけど、こないだ最長経路のプログラムでウソプログラム書いちゃったなぁ…




No.927

Re:アルゴリズム
投稿者---あかま(2004/01/02 08:17:00)


バグ。
重量0のアイテム作ると0の割り算で止まります。

No.928

ありがとうございます!
投稿者---新米さん(2004/01/02 17:49:59)


とても助かりました(>_<)ありがとうございます!!