我认为 Tyler Durden 的想法是正确的。但是您不必对所有元素求和,而且您基本上可以贪婪地完成它,因此您可以大大减少循环。在 C++ 中:
#include <iostream>
#include <algorithm>
using namespace std;
#define FI(n) for(int i=0;i<(n);i++)
int m, n, k;
int a[] = { 12, 43, 1, 4, 3, 5, 13, 34, 24, 22, 31 },
e[20];
inline int max(int i) { return n-k+i+1; }
void print(int e[], int ii, int sum)
{ cout << sum << '\t';
FI(ii+1) cout << e[i]<<','; cout<<'\n';
}
bool desc(int a, int b) { return a>b; }
int solve()
{ sort(a, a+n, desc);
cout <<"a="; FI(n) cout << a[i]<<','; cout<<"\nsum\tindexes\n";
int i,sum;
i = e[0] = sum = 0;
print (e,i,a[0]);
while(1)
{ while (e[i]<max(i) && sum+a[e[i]]>=m) e[i]++;
if (e[i]==max(i))
{ if (!i) return -1; // FAIL
cout<<"*"; print (e,i,sum);
sum -= a[e[--i]++];
} else // sum+a[e[i]]<m
{ sum += a[e[i]];
print (e,i,sum);
if (i+1==k) return sum;
e[i+1] = e[i]+1;
i++;
}
}
}
int main()
{ n = sizeof(a)/sizeof(int);
k = 3;
m = 39;
cout << "n,k,m="<<n<<' '<<k<<' '<<m<<'\n';
cout << solve();
}
对于 m=36,它给出了输出
n,k,m=11 3 36
a=43,34,31,24,22,13,12,5,4,3,1,
sum indexes
43 0,
34 1,
*34 1,10,
31 2,
35 2,8,
*35 2,8,11,
34 2,9,
35 2,9,10,
35
对于 m=37,它给出
n,k,m=11 3 37
a=43,34,31,24,22,13,12,5,4,3,1,
sum indexes
43 0,
34 1,
*34 1,10,
31 2,
36 2,7,
*36 2,7,11,
35 2,8,
36 2,8,10,
36
(最后一次尝试:对于 m=39,它也给出了正确答案,38)
输出:最后一个数字是总和,它上面的行有索引。带星号的行在回溯之前,因此行的最后一个索引太高。运行时间应该是 O(k*n)。
对于难以理解的代码,我们深表歉意。我可以清理它并根据要求提供解释,但我现在还有另一个项目要到期;)。