概述
背包问题简单点说:这里有很多大小不同的物品, 价值不等,然后包就这么大,装哪些物品,能达到包里物品价值最大化。
思路
方法一:回溯
组合各种的东西的各种组合,找到价值最大物品组合。
方法二:
每种物品只有两个状态,装或者不装。如果装,就要继续求剩余容量下,剩余物品的最大装载价值;如果不装,就是求包容量下的剩余物品的最大装载价值。
换言之,就把问题分解成了两个子问题的最优解,这样递归下去,就找到了最优物品组合。
源码
本文主要是以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;
}
运行结果
略