经典背包问题---回溯和动态规划

概述

背包问题简单点说:这里有很多大小不同的物品, 价值不等,然后包就这么大,装哪些物品,能达到包里物品价值最大化。

思路

方法一:回溯
组合各种的东西的各种组合,找到价值最大物品组合。
方法二:
每种物品只有两个状态,装或者不装。如果装,就要继续求剩余容量下,剩余物品的最大装载价值;如果不装,就是求包容量下的剩余物品的最大装载价值。
换言之,就把问题分解成了两个子问题的最优解,这样递归下去,就找到了最优物品组合。

源码

本文主要是以C、C++、QT为基础进行编程,运行前简单修改即可。测试入口函数为 void Test_Knapsack()。

#include <qglobal.h>
#include "log.h"
#include "QtMath"
#include "QTime"
#include "QList"



static const quint32 g_KCapacity = 100;//背包承重
static quint32 g_KBestValue = 0;//背包物品最优价值
static QList<quint32> g_KBestItemList;

static const quint32 ITEM_SUM = 10;//物品数量
static quint32 g_aItemWeight[ITEM_SUM];
static quint32 g_aItemValue[ITEM_SUM];
static quint32 g_aWeightBackup[ITEM_SUM];
static quint32 g_aValueBackup[ITEM_SUM];
static const quint32 ITEM_WEIGHT_MAX = 90;
static const quint32 ITEM_VALUE_MAX = 50;

static QList<quint32> g_TempItemList;
static quint32 g_TempWeightSum = 0;
static quint32 g_TempValueSum = 0;



void Knapsack_ClearBestResult()
{
    g_KBestValue = 0;
    g_KBestItemList.clear();
}
void Knapsack_ClearTempPara()
{
    g_TempWeightSum = 0;
    g_TempValueSum = 0;
    g_TempItemList.clear();
}
void Knapsack_OutputBest()
{
    quint32 loop = 0;
    quint32 index;

    qDebug()<<endl<<"BestValueSum:"<<g_KBestValue
           <<"count:"<<g_KBestItemList.count();
    while(loop<(quint32)g_KBestItemList.count())
    {
        index = g_KBestItemList.at(loop);
        qDebug()<<index<<",value="<<g_aItemValue[index]
                       <<",weight="<<g_aItemWeight[index];
        loop++;
    }
}
void Knapsack_OutputItemWeightAndValue()
{
    quint32 loop = 0;

    printf("\nItemWeightAndValue:");
    while(loop<ITEM_SUM)
    {
        //qDebug()<<g_aItemWeight[loop]<<" ";
        printf("w=%d;v=%d; ",g_aItemWeight[loop],g_aItemValue[loop]);
        loop++;
    }
}

void Knapsack_InitItemWeightValue()//在1-50随机重量和价值
{
    quint32 loop = 0;
    QTime time = QTime::currentTime();

    qsrand(time.msec());
    while(loop<ITEM_SUM)
    {
        g_aItemWeight[loop] = qrand()%ITEM_WEIGHT_MAX +1;
        g_aItemValue[loop] = qrand()%ITEM_VALUE_MAX +1;
        loop++;
    }

    #if 0   //debug  ITEM_SUM=10;
    loop = 0;
    g_aItemWeight[loop]=46;g_aItemValue[loop++]=9;
    g_aItemWeight[loop]=7;g_aItemValue[loop++]=34;
    g_aItemWeight[loop]=56;g_aItemValue[loop++]=23;
    g_aItemWeight[loop]=69;g_aItemValue[loop++]=18;
    g_aItemWeight[loop]=73;g_aItemValue[loop++]=22;
    g_aItemWeight[loop]=50;g_aItemValue[loop++]=19;
    g_aItemWeight[loop]=35;g_aItemValue[loop++]=14;
    g_aItemWeight[loop]=22;g_aItemValue[loop++]=17;
    g_aItemWeight[loop]=11;g_aItemValue[loop++]=20;
    g_aItemWeight[loop]=92;g_aItemValue[loop++]=17;
    #endif//debug end

    #if 0   //debug ITEM_SUM=3;
    loop = 0;
    g_aItemWeight[loop]=29;g_aItemValue[loop++]=24;
    g_aItemWeight[loop]=13;g_aItemValue[loop++]=43;
    g_aItemWeight[loop]=56;g_aItemValue[loop++]=48;
    #endif

    Knapsack_OutputItemWeightAndValue();
    memcpy(&g_aWeightBackup[0], &g_aItemWeight[0], sizeof(g_aWeightBackup));
    memcpy(&g_aValueBackup[0], &g_aItemValue[0], sizeof(g_aValueBackup));
}
void Knapsack_SortItemWeight()//从轻到重bubble sort
{
    quint32 i=0, j=0;
    quint32 temp;

    for(i=ITEM_SUM-1;i>0;i--)
    {
        for(j=0;j<i;j++)
        {
            if(g_aItemWeight[j] > g_aItemWeight[j+1])
            {
                //exchange j and j+1
                temp = g_aItemWeight[j];
                g_aItemWeight[j] = g_aItemWeight[j+1];
                g_aItemWeight[j+1] = temp;

                temp = g_aItemValue[j];
                g_aItemValue[j] = g_aItemValue[j+1];
                g_aItemValue[j+1] = temp;
            }
        }
    }

    Knapsack_OutputItemWeightAndValue();
}
void Knapsack_ResetItemWeightValue_BeforSort()
{
    memcpy(&g_aItemWeight[0], &g_aWeightBackup[0], sizeof(g_aWeightBackup));
    memcpy(&g_aItemValue[0], &g_aValueBackup[0], sizeof(g_aValueBackup));
}

/****************************************************/
void Knapsack_Solution_1_GetBestItem(quint32 bestItemSum, quint32 u32currentIndex,
                              quint32 startIndex, quint32 endIndex)
{
    quint32 loop = startIndex;
    while(loop <= endIndex)
    {
        if((g_aItemWeight[loop]+g_TempWeightSum) <= g_KCapacity)//重量合适
        {
            g_TempItemList.append(loop);
            g_TempWeightSum += g_aItemWeight[loop];
            g_TempValueSum += g_aItemValue[loop];

            if(u32currentIndex == (bestItemSum-1))//数量找够了
            {
                //compare best_list and temp_list
                if(g_TempValueSum > g_KBestValue)
                {
                    //update best_list
                    g_KBestItemList = g_TempItemList;
                    g_KBestValue = g_TempValueSum;
                    Knapsack_OutputBest();
                    //need roll-back
                }
                else
                {
                    //need roll-back
                }
            }
            else
            {
                Knapsack_Solution_1_GetBestItem(bestItemSum, u32currentIndex+1,
                                                loop+1, endIndex);
                //need roll-back
            }

            //do roll-back
            g_TempItemList.removeOne(loop);
            g_TempWeightSum -= g_aItemWeight[loop];
            g_TempValueSum -= g_aItemValue[loop];
        }
        else
        {
            break;//sort的好处体现在这里
        }
        loop++;
    }
}

/*
 *dynamic programming
 *item_sum: 1,2,3...ITEM_SUM
*/
quint32 Knapsack_Solution_2_GetBestValue(quint32 item_sum, quint32 capacity)
{
    quint32 value1=0, value2=0;

    if(item_sum > ITEM_SUM || 0 == item_sum)
    {
        return 0;
    }

    if(0 == capacity)
    {
        return 0;
    }

    //qDebug()<<"item_sum:"<<item_sum<<"capacity:"<<capacity;
    if(1 == item_sum)
    {
        if(capacity >= g_aItemWeight[0])
        {
            value1 = g_aItemValue[0];
        }

        //qDebug()<<"item_sum:"<<item_sum<<"capacity:"<<capacity
        //        <<"value:"<<value1<<value2;
        return value1;
    }

    if(capacity >= g_aItemWeight[item_sum-1])//可以放得下这个物品
    {
        //放
        value1 = g_aItemValue[item_sum-1]
                 + Knapsack_Solution_2_GetBestValue(item_sum-1,
                                       capacity-g_aItemWeight[item_sum-1]);

    }
    //不放
    value2 = Knapsack_Solution_2_GetBestValue(item_sum-1, capacity);

    //qDebug()<<"item_sum:"<<item_sum<<"capacity:"<<capacity
    //        <<"value:"<<value1<<value2;
    if(value1 > value2)//放
    {
        return value1;
    }

    return value2;
}
//回溯最优Item List
void Knapsack_Solution_2_GetBestItemList(quint32 item_sum, quint32 capacity)
{
    quint32 i=item_sum;
    while(i>0)
    {
        if(capacity < g_aItemWeight[i-1])//不可以放得下这个物品
        {
            i--;
            continue;
        }

        if(Knapsack_Solution_2_GetBestValue(i, capacity) !=
            Knapsack_Solution_2_GetBestValue(i-1, capacity))
        {
            g_KBestItemList.append(i-1);
            g_KBestValue += g_aItemValue[i-1];
            capacity -= g_aItemWeight[i-1];
        }
        i--;
    }
}

void Test_Knapsack()
{
    quint32 bestValue1=0, bestValue2=0;
    Knapsack_InitItemWeightValue();

    /************* solution_1 *************/
    Knapsack_ClearBestResult();
    Knapsack_ClearTempPara();
    Knapsack_SortItemWeight();
    quint32 bestItemSum = 1;
    while(bestItemSum <= ITEM_SUM)
    {
        Knapsack_ClearTempPara();
        Knapsack_Solution_1_GetBestItem(bestItemSum, 0, 0, ITEM_SUM-1);
        bestItemSum++;
    }
    bestValue1 = g_KBestValue;
    qDebug()<<endl<<"--------------solution--------------";

    /************* solution_2 *************/
    Knapsack_ResetItemWeightValue_BeforSort();
    Knapsack_ClearTempPara();
    Knapsack_ClearBestResult();
    bestValue2 = Knapsack_Solution_2_GetBestValue(ITEM_SUM, g_KCapacity);
    Knapsack_Solution_2_GetBestItemList(ITEM_SUM, g_KCapacity);
    Knapsack_OutputBest();

    qDebug()<<endl<<"-----------bestValue1:"<<bestValue1<<"; bestValue2:"<<bestValue2<<endl;
}

运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值