从数列1,2,3,......,n中随意取出几个数,使其和等于m

问题描述:
    输入两个整数n和m,从数列1,2,3,.......n中随意去几个数,使其和等于m,要求将其中所有可能的组合列出来。

解决思路
    这个问题其实是背包问题的变形,给出两种解决方法。
    解法一:
    用递归,效率可能低了点。假设问题的解为F(n,m),可分为两个子问题F(n-1,m-n)和F(n-1,m)。对于这两个问题递归求解,求解的过程中,如果找到了符合条件的数字组合,则打印出来。
    解法二:
    用循环,其实就是枚举所有组合。对于n,组合数应该为2^n。我们可以用一个数字i来表示组合。如果i = 5,其二进制形式为101,相应的组合为{1,3}。也就是说,二进制的每一位都表示一个数字,bit0代表数字1,bit1代表数字2,依次类推。当某位为1,表示选中了该位所表示的数字。

参考代码
  1. #include <iostream>
  2. using namespace std;

  3. //函数功能:从数列1,2,3......n中随意取几个数,使其和等于m
  4. //函数参数:n为当前最大值,m为剩余值,flag标记选中与否,len为flag的容量
  5. //返回值: 无
  6. void BagProlem_Solution1(int n, int m, int *flag, int len)
  7. {
  8.     if(< 1 || m < 1)
  9.     {
  10.         return;
  11.     }

  12.     if(< m)
  13.     {
  14.         flag[- 1] = 1;
  15.         BagProlem_Solution1(- 1, m - n, flag, len); //选了n
  16.         flag[- 1] = 0;
  17.         BagProlem_Solution1(- 1, m, flag, len);     //不选n
  18.     }
  19.     else
  20.     {
  21.         flag[- 1] = 1; //>= m,选中m即可(n = m)
  22.         for(int i = 0; i < len; i++)
  23.         {
  24.             if(flag[i] == 1)
  25.             {
  26.                 cout << i + 1 << " ";
  27.             }
  28.         }
  29.         cout << endl;
  30.         flag[- 1] = 0; //不选m,继续递归。比如n = 10, m = 8,求出{1,7}后,仍需继续,{1,3,4}{1,2,5}都是解
  31.         BagProlem_Solution1(- 1, m, flag, len);
  32.     }
  33. }

  34. //函数功能:从数列1,2,...n中随意选取几个数,使其和等于m
  35. //函数参数:n为当前最大值,m为剩余值
  36. //返回值: 无
  37. void BagProlem_Solution2(int n, int m)
  38. {
  39.     if(< 1 || m < 1)
  40.     {
  41.         return;
  42.     }
  43.     if(> m)
  44.     {
  45.         n = m;
  46.     }

  47.     int num = 1 << n;    //枚举次数
  48.     for(int i = 1; i < num; i++)
  49.     {
  50.         int sum = 0;
  51.         int j, k;
  52.         for(= i, k = 1; j != 0; j >>= 1, k++)
  53.         {
  54.             if(& 1)
  55.             {
  56.                 sum += k;
  57.             }
  58.         }
  59.         if(sum == m)//如果满足,打印结果
  60.         {
  61.             for(= i, k = 1; j != 0; j >>= 1, k++)
  62.             {
  63.                 if(& 1)
  64.                 {
  65.                     cout << k << " ";
  66.                 }
  67.             }
  68.             cout << endl;
  69.         }
  70.     }
  71. }

  72. int main()
  73. {
  74.     int n, m;
  75.     cout<<"please enter n and m : ";
  76.     cin>>n>>m;

  77.     int *flag = new int[n];
  78.     for(int i = 0; i < n; i++)
  79.     {
  80.         flag[i] = 0;
  81.     }
  82.     BagProlem_Solution1(n, m, flag, n);
  83.     cout<<endl;
  84.     BagProlem_Solution2(n, m);
  85.     delete [] flag;
  86.     return 0;
  87. }
    上述方法二,思路确实很巧妙,但是有一定的限制,对于32位机器来说,只能枚举32个数。
### 回答1: 求1到100的数列和,即1+2+3+...+100的结果。 解法一:暴力求和法 将1到100的数列依次相加,即可得到结果。 1+2+3+...+98+99+100=505 解法二:等差数列求和法 1到100的数列是一个等差数列,公差为1,首项为1,末项为100。根据等差数列求和公式,可得: S = n(a1 + an) / 2 其,S为数列和,n为数列,a1为首项,an为末项。 将n取100,a1取1,an取100代入公式,即可得到结果。 S = 100(1 + 100) / 2 = 505 因此,1到100的数列和为505。 ### 回答2: 这道题是一道简单的学题,初学生可能会想到将字一个一个相加,这样会非常耗时。其实,如果将数列按照相加的顺序倒过来,即100 99 98 ...... 3 2 1,再将相邻的两个相加,就有100+1=101,99+2=101,98+3=101......等等,这样每两个字的和都是101,而100个字分为了50组,因此这个数列的和就是101*50=5050。 实际上,在学习,我们经常遇到各种类型的数列求和,如等差数列、等比数列等等。这些问题都可以通过找规律或者学公式来解决。 对于等差数列,其首项为a1,公差为d,第n项为an,则这个等差数列的前n项和Sn为:Sn = n(a1+an)/2。 对于等比数列,其首项为a1,公比为q(q≠0),第n项为an,则这个等比数列的前n项和Sn为:Sn = a1(1-q^n)/(1-q)。 这些公式其实并不难记,但在使用过程,我们需要适当地进行变形和加减混合运算。 通过数列求和问题,可以锻炼我们的学思维能力和逻辑推理能力。在学习过程,我们可以多动手练习、多思考和与同学讨论,不断提高自己的学能力。 ### 回答3: 首先,我们可以使用等差数列求和公式来求解。由于这个数列是从1开始,公差为1,且共有100个,所以可以得到: 1+2+3+...+100 = (1+100)*100/2 = 5050 上述计算过程用到了等差数列求和公式,即S_n = (a_1+a_n)*n/2,其a_1为数列的首项,a_n为数列的末项,n为数列的项。 除此之外,我们还可以尝试使用递归的方式求解。具体思路是,对于一个n,它的前一个为n-1,则数列的和可以表示为n + Sum(n-1),其Sum(n-1)表示前n-1个的和。当n=1时,前面没有,所以Sum(1)=1。因此,我们可以写出如下的递归函: def Sum(n): if n == 1: return 1 else: return n + Sum(n-1) 最后,我们在调用Sum(100)时,便可以得到数列1到100的和,即5050。这种方法可以帮助我们更好地理解递归的思想,也是一种比较通用的求解数列和的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值