将数字n分成k个不同数字的总和

时间:2016-12-07 07:11:07

标签: c++ algorithm

我有一个数字n,我必须将其分成k个数,使得所有k个数字都是不同的,k个数的总和等于n,k是最大值。例如,如果n是9,那么答案应该是1,2,6。如果n是15,那么答案应该是1,2,3,4,5 这就是我尝试过的 -

void findNum(int l, int k, vector<int>& s)
{
    if (k <= 2 * l) {
        s.push_back(k);
        return;
    }
    else if (l == 1) {
        s.push_back(l);
        findNum(l + 1, k - 1, s);
    }
    else if(l == 2) {
        s.push_back(l);
        findNum(l + 2, k - 2, s);
    }
    else{
        s.push_back(l);
        findNum(l + 1, k - l, s);
    }

}

最初k = n且l = 1.结果数字存储在s中。该解决方案即使将数字n作为k个不同数字的总和返回,但它不是最优解(k不是最大值)。 n = 15的示例输出是1,2,4,8。应该做出哪些改变才能得到正确的结果?

2 个答案:

答案 0 :(得分:6)

Greedy算法适用于此问题。刚开始总结从1到msum(1...m) <= n。一旦超过,将多余的部分添加到m-1。从1到m | m-1的数字将是答案。

例如

18
1+2+3+4+5 < 18
+6 = 21 > 18
So, answer: 1+2+3+4+(5+6-(21-18))

28
1+2+3+4+5+6+7 = 28
So, answer: 1+2+3+4+5+6+7

伪代码(在恒定时间内,复杂度为O(1))

Find k such that, m * (m+1) > 2 * n
Number of terms = m-1
Terms: 1,2,3...m-2,(m-1 + m - (sum(1...m) - n))

答案 1 :(得分:0)

sum 可以在 {1, ... , m} 中划分为 k 个项,如果 min(k) <= sum <= max(k,m), with

min(k) = 1 + 2 + .. + k = (k*(k+1))/2

max(k,m) = m + (m-1) + .. + (m-k+1) = k*m - (k*(k-1))/2

因此,您可以使用以下伪代码:

fn solve(n, k, sum) -> set or error
  s = new_set()
  for m from n down to 1:
    # will the problem be solvable if we add m to s?
    if min(k-1) <= sum-m <= max(k-1, m-1) then
      s.add(m), sum-=m, k-=1
  if s=0 and k=0 then s else error()