1. 程式人生 > >貪心演算法解決0-1揹包問題

貪心演算法解決0-1揹包問題

揹包問題描述如下:  已知

   揹包容量M=120

   物品種類數n=10

   各種物品的總效益pi(i=1,2,………10) : 50,60,70,80,90,80,70,60,50,40

   各種物品的總重量wi(i=1,2………10) : 17,30,25,41,80,70,64,56,47,38

: 各種物品所取重量佔其總重量的比例xi(i=1,2,…..10),滿足0<=xi<=1,

按三種不同的量度標準分別計算所得最大總效益

1. 按效益值由大到小取物品

2.  按重量值由小到大取物品

3. 按比值pi/wi的值由大到小取物品

貪心演算法思想

資料結構採用結構體來表示一個物品。按照各種量度標準排序物品。對於每一種排序結果,在揹包容量內,選擇量度最大的物品,繼續選擇次量度最大的物品,直到選到當前量度最大物品的重量大於揹包剩餘容量時(容不下),放入物品的一部分,這部分和揹包剩餘容量相等。打印出各物品是否被選擇,或者被選擇的比例。

程式程式碼

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <cstdio>
using namespace std;
struct form {
    int i;                       //為方便後序列印結果,設定物品序號
    int pi;
    int wi;
    float xi;
    int flag;                   //標誌一整個物品被選取
    float floflag;              //標誌物品被選取的那一部分
};
int bag, thingNum;
int cmpPi( form a, form b )     //按效益值從大到小排序
{
    return a.pi > b.pi;
}
int cmpWi( form a, form b )     //按重量從小到大排序
{
    return a.wi < b.wi;
}
int cmpXi( form a, form b )     //按比例從大到小排序
{
    return a.xi > b.xi;
}
void print( form *things, int thingNum )
{
    printf( "物品序號   " );
    for( int i = 0; i < thingNum; i++ )
        printf( "%-6d", i );
    printf( "總效益\n           " );
    float ans = 0;                                           //總效益,邊列印邊計算
    for( int i = 0; i < thingNum; i++ ) {
        for( int j = 0; j < thingNum; j++ ) {
            if( things[j].i == i ) {
                if( things[j].floflag != 0 ) {
                    printf( "%-6.3f", things[j].floflag );
                    ans += things[j].floflag * things[j].pi ;
                    things[j].floflag = 0;                       //置零初始化
                }
                else {
                    printf( "%-6d", things[j].flag );
                    if( things[j].flag == 1 )
                        ans += things[j].pi ;
                    things[j].flag = 0;                           //置零初始化
                }
                continue;
            }
        }
    }
    printf( "%-6.2f\n", ans );
    for( int i = 0; i < 100; i++ )
        printf( "-" );
    printf( "\n" );
}
void select( form *things )                                     //選取物品
{
    int res = bag;
    for( int i = 0; i < thingNum; i++ ) {
        if( things[i].wi < res ) {
            things[i].flag = 1;
            things[i].floflag = 0;
            res -= things[i].wi;
        }
        else {
            things[i].flag  = 0;
            things[i].floflag = ( 1.0 * res ) / things[i].wi;
            break;
        }
    }
}
void value( form *things )
{
    sort( things, things + thingNum, cmpPi );
    select( things );
    printf( "按效益值\n" ) ;
    print( things, thingNum );
}
void weight( form *things )
{
    sort( things, things + thingNum, cmpWi );
    printf( "\n" );
    select( things );
    printf( "按重量\n" );
    print( things, thingNum );
}
void speVal( form *things )
{
    sort( things, things + thingNum, cmpXi );
    cout << endl;
    select( things );
    printf( "按比值\n" ) ;
    print( things, thingNum );
}
int main( ) {
    printf( "請輸入揹包容量,物品數目:\n" );
    scanf( "%d%d", &bag, &thingNum );
    printf( "輸入每個物品的效益和重量:\n" );
    form things[thingNum];
    for( int i = 0; i < thingNum; i++ ) {
        scanf( "%d%d", &things[i].pi, &things[i].wi );
        things[i].i = i;
        things[i].xi = 1.0 * things[i].pi / things[i].wi;
        things[i].flag = things[i].floflag = 0;           //初始化
    }
    value( things );                                       //按效益值
    weight( things );                                        //按重量值
    speVal( things );                                        // 按比值
    return 0;
}

題目資料樣例

120 10
50 17
60 30
70 25
80 41
90 80
80 70
70 64
60 56
50 47
40 38

輸出樣例