寻找和为定值的任意个数(01背包)

来源:互联网 发布:淘宝火车票网上订票 编辑:程序博客网 时间:2024/06/03 03:45

这个问题是在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;}

如此。

0 0
原创粉丝点击