这个问题是在July的《编程之法》上看到的,题目要求是:输入两个数字n与sum,在1~n中寻找哪些数字之和等于sum。
很明显这是个典型的01背包问题,因为每一个元素只有要与不要两种选择~
#include<list>
#include<iostream>
using namespace std;
list<int>list1;
void find_factor(int sum, int n)
{
// 递归出口
if(n <= 0 || sum <= 0)
return;
if(n>sum)
n=sum;
// 输出找到的结果
if(sum == n)
{
// 反转list
list1.reverse();
for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
cout << *iter << " + ";
cout << n << endl;
list1.reverse();
}
list1.push_front(n); //典型的01背包问题
find_factor(sum-n, n-1); //放n,n-1个数填满sum-n
list1.pop_front();
find_factor(sum, n-1); //不放n,n-1个数填满sum
}
int main()
{
int sum, n;
cout << "请输入你要等于多少的数值sum:" << endl;
cin >> sum;
cout << "请输入你要从1.....n数列中取值的n:" << endl;
cin >> n;
cout << "所有可能的序列,如下:" << endl;
find_factor(sum,n);
return 0;
}
后来自己又在想,这样局限性有点大,如果数组元素是任意的呢?即: 数组元素任意,输入sum,求所有和为sum的组合
可以思考一下:若数组元素任意,则处理之前,必须进行排序(原本可能是无序的),使用快速排序实现此功能。然后实际上还是一个背包问题,只不过不是01背包,可以说算是完全背包吧,因为每个元素科可以有多个,但是在逻辑上仍然将它们看作是单独的存在,两种选择:要或不要,在上边代码的基础上进行改进:
#include<iostream>
#include<cstdio>
#include<list>
using namespace std;
list<int> list1;
int number; //统计总共多少种符合要求的组合
int find(int s[],int sum){ //在数组s中寻找比sum小的最大的一个元素的下标,若不存在则返回-1
int i;
for (i=0;s[i]<=sum&&i<10;i++);
return i-1;
}
void swap(int *a,int *b){ //交换数组中两个元素的下标
int t;
t=*a;
*a=*b;
*b=t;
}
void sort(int s[],int left,int right){ //快速排序
if(left>=right)
return ;
int i,j,mid;
mid =(left+right)/2;
swap(&s[left],&s[mid]);
for(j=left,i=left+1;i<=right;i++)
if(s[i]<s[left]){
swap(&s[i],&s[++j]);
}
swap(&s[left],&s[j]);
sort(s,left,j-1);
sort(s,j+1,right);
}
void find_factor(int s[],int sum,int n){
if(n==-1) //n==-1则相当于:s[0]被考虑过(包含加或不加)后仍旧不能满足sum,即之前的组合状态不可行,直接返回。
return ;
if(sum<s[n]){ //如果sum小于当前区域内的最大元素,则执行find()函数找到小于它的最后一个元素,若找不到,则说明在
n=find(s,sum); // 之前的组合状态不可行,直接返回。
if(n==-1)
return;
}
if(sum==s[n]){ //说明之前的组合状态可行
number++; //统计所有符合要求的组合的个数
list1.reverse(); //反转list
for(list<int>::iterator iter =list1.begin();iter!=list1.end();iter++)
cout<<*iter<<"+";
cout<<s[n]<<endl;
list1.reverse();
}
list1.push_front(s[n]); //非常典型的01背包问问题
find_factor(s,sum-s[n],n-1);//放s[n],用剩余n-1个元素 填满 sum-s[n]
list1.pop_front();
find_factor(s,sum,n-1); //不放s[n],用剩余n-1个元素 填满 sum
}
int main(void){
int i,j,k,sum;
int s[10];
printf("请输入想要的sum:\n");
scanf("%d",&sum);
printf("请输入数组元素:\n");
for(i=0;i<10;i++)
scanf("%d",s+i);
sort(s,0,9); //快排
/* for(i=0;i<10;i++){
printf("%d ",s[i]);
}
*/
printf("符合要求的组合:\n");
find_factor(s,sum,9);
printf("总共%d种组合\n",number);
return 0;
}
如此。