自然数拆分

题目:

给出summinmaxn四个正整数,请输出所有将sum拆分为n个递增的正整数(允许相等)之和,其中每个正整数k都满足:min <= k <= max

 

少侠的博客看到这道题,就随手做了下。该题与输出N个数取M个数的所有组合类似,只不过限定了M个数的和以及取值范围。可以先用贪心算法构造一个最小的组合,然后调整这个组合,得到下一个组合。显然应该从后往前找到一个数字,该数增加1,再调整该数后面的数。这个数就是:从后往前第一个与最后一个数的差值大于1的数(因为,如果差值小等于1,无法调整后面的数得到一个符合要求的组合)。


//www.cnblogs.com/flyinghearts

#include
<iostream>
#include
<vector>
#include
<cassert>
using std::cout;
using std::vector;

static inline void print(int arr[], int len, int n)
{
  cout 
<< n << " = ";
  
for (int i = 0; i < len - 1++i) cout << arr[i] << " + ";
  cout 
<< arr[len - 1];
  cout 
<< "\n";
}

static inline void init(int arr[], int len, int sum, int min, int max)
{
  sum 
-= min * len;
  
int i = len;
  
while ((sum -= max - min) > 0)  arr[--i] = max;
  arr[
--i] = sum + max;
  
while (i > 0) arr[--i] = min;
}

void solve(int sum, int n, int min, int max)
{
  
if (n <= 1 || min > max || min <= 0 || sum < n * min || sum > n * max) return;
  
static vector<int> v;
  v.resize(n);
  
int *first = &v[0];
  
int *last = &v[n - 1];
  init(first, n, sum, min, max);
  
while (1) {
    print(first, n, sum);
    
int *= last - 1;
    
//若最后两个数差值大等于2,则直接调整
    if (*last - *>= 2) { ++*p; --*last; continue; }
    
int tt = *last - 2
    
int ss = *last + *p;
    
//从后往前找到第一个与最后一个数差值大等于2的数,从该数开始调整
    while (-->= first && *> tt) { ss += *p;}
      
if (p < first) break;
    
//if (*p == tt && *last != *(last - 1)) { ++*p; --*last; continue;} 
      ++*p; 
      init(p 
+ 1, last - p, ss - 1*p, max);
  }
  cout 
<< "\n";
}

int main()
{
  solve(
10415);
  solve(
10522);
}


 

 

posted @ 2010-12-31 23:39  flyinghearts  阅读(1162)  评论(0编辑  收藏  举报