背包0-1问题不详细解释
问题:输入两个整数n和m,从数列1,2,3,...,n中随意取几个数,使其和等于m,将其所有可能的组合列出来。
求解思路:
1.首先判断,如果n>m,则n中大于m的数不可能参与组合,此时置n=m;
2.将最大的数n加入且n==m,则满足条件,输出;
3.将n分两种情况求解:n没有加入,取n=n-1,m=m,递归;
4.n加入,取n=n-1,m=m-n,递归。
5.结束。
这个题是从欧立奇那个神经病的程序员面试宝典里面来的,程序写得相当简洁,一步到另一步怎么来的,写得特tm简单,看得我气得要死,单步跟踪也不知道tmd是怎么想出来的。我写个小小的注释,很明显,我还没有看懂。
#include <iostream>
#include <string>
using namespace std;
int mVal,nVal;
int *pOut;
//把体积为n的新木块装到体积为m的盒子里
void calFun(int m,int n)
{
//盒子满了,或者最小的都塞不进去了,或者塞进去大了
if(m<1||n<1||(n==1&&m!=1))
{
return;
}
//如果盒子剩余的空间和新木块的大小一样,也就是盒子满了
if(m==n)
{
//n放进盒子里,m也满了,开始打印
pOut[n]=1;
for(int i=1;i<=nVal;++i)
{
if(pOut[i])
{
cout<<i<<" ";
}
}
cout<<endl;
}
//把n放进盒子里的情况
pOut[n]=1;
//盒子剩余空间m-n,继续放n-1
calFun(m-n,n-1);
//不把n放盒子里的情况
pOut[n]=0;
//盒子剩余空间m,放n-1
calFun(m,n-1);
}
int main(int argc,char* argv[])
{
//输入和
cout<<"m:";
cin>>mVal;
//输入待选数
cout<<"n:";
cin>>nVal;
//筛选待选数
if(mVal<nVal)
{
//n肯定比m小,因为比m大的数没有意义
nVal=mVal;
}
//初始化被选标记都为0
pOut=new int[nVal+1];
memset(pOut,0,(nVal+1)*sizeof(int));
calFun(mVal,nVal);
delete []pOut;
return 0;
}