33,007
社区成员
发帖
与我相关
我的任务
分享
// ---------------------------------------------------
// 问题描述: 一个背包可以装M个重量,有N个物品,重量为
// W1,W2, ..... ,Wn 如何正好装满背包?
// 注1: 必须用非递归解决
// 注2: 一般要求一个解,我的程序是得到所有解
// 注3: 由于32位unsigned int限制,最多32个物品
//
// 这就是最简单的背包问题,没有加入价值因素
// 真正的0-1背包问题是有价值的....
// 好多人竟然不会做这题...我就好好写个注释详细的吧..
//
// 递归写法我相信很多人都会...但是非递归就傻眼了
// 其实也很简单...无非是模拟递归...用标记数组而已
// 认真看看那个模拟递归的for循环...
// 这种for循环应该算是状态转移了..有点像动态规划
//
// 另外,程序根本没有优化...这样是最好懂的...
// 优化的方法也很多...比如先排序...
// 然后用类似剪枝的方法修改状态转移的for循环
// 或者根本就用3层循环描述状态转移方程...那都是后话了
// 如果你真的很想了解背包问题
// 请Google一下 《背包问题九讲》
//
//
// PS:竟然打了这么多注释...汗一下...
//
// BaihowFF
// 08.11.9
// ---------------------------------------------------
#include <iostream>
using namespace std;
// 如果你使用的是万恶的VC6,可以加上下面这句,省的出错
#define for if(1) for
// 物品总数
const int N_ITEM=5;
// 背包能装的重量
const int BAG=15;
// 初始化每个物品的重量
int item[N_ITEM]={2,3,5,7,8};
// 标记数组
int flag[N_ITEM]={0,0,0,0,0};
// 结果计数器
int resultCount(0);
// 打印结果
void Print();
int main()
{
// 一开始打印一下已知条件
cout<<"BAG Weight:"<<BAG<<endl;
cout<<"Item Number:"<<N_ITEM<<endl;
for (int i=0;i!=N_ITEM;i++)
{
cout<<"Item."<<i+1<<" W="<<item[i]<<"\t";
}
cout<<endl;
// 所有可能性次数,即2的n次方
// 注意最大不能超过4G,即不能有32个以上物品
// 实际上有20个电脑就得算一下了...那有1M的可能了
// 一般写算法不能超过1M的时间复杂度...否则瞬间无结果
// 当然..我说的是台式电脑...如果你拿曙光5000就是另外的事情了
unsigned int count(0);
unsigned int all_count(1);
for (int i=0;i!=N_ITEM;i++)
{
all_count*=2;
}
while (1)
{
// 模拟递归...列举所有flag数组可能
// 其实就这个for循环是关键
for (int i=0;i!=N_ITEM;i++)
{
if ( 0 == flag[i] )
{
flag[i]=1;
continue;
}
// 下面换成if ( 1 == flag[i] )可能更好理解
else
{
flag[i]=0;
break;
}
}
// 如果你不理解上面的循环
// 可以打开下面注释掉的循环
// 把#if(0)改成#if(1)就可以了
// 看看flag数组变化
// 在纸上画一下...
// 应该很容易理解哦~~~
// ^_^
#if(0)
for (int i=0;i!=N_ITEM;i++)
{
cout<<flag[i];
}
cout<<endl;
#endif
// 判断时候装满背包
// 多加一个括号...使得临时变量每次重新创建而已
// 我认为...这样temp比较容易懂...呵呵...
{
// 本次重量,初始化0
int temp(0);
// 按标记计算所有选中物品重量和
for (int i=0;i!=N_ITEM;i++)
{
if ( 1 == flag[i] )
{
temp+=item[i];
}
}
// 满足背包重量就打印
if ( temp == BAG )
{
resultCount++;
Print();
}
}
// 如果遍历了所有情况就break掉while(1)循环
count++;
if (count==all_count)
{
break;
}
}
return 0;
}
// 额..竟然打了这么多注释..这个函数我就不解释了...
void Print()
{
cout<<"Result "<<resultCount<<endl;
for (int i=0;i!=N_ITEM;i++)
{
if ( 1 == flag[i] )
{
cout<<"Item."<<i+1<<" Weight:"<<item[i]<<"\t";
}
}
cout<<endl;
}