使用您的示例值提出此问题的另一种方法是:您可以从 {0,2,3,4,5,6,7,9,11,14, 17,21} 使得总和为 44。
一旦你有了这些答案,你就可以统一选择一个,将它们洗牌到你的属性中,每个属性加 7。
一些示例答案:
{21, 21, 2, 0, 0, 0} {21, 17, 6, 0, 0, 0} {21, 17, 4, 2, 0, 0}
{21, 17, 3, 3, 0, 0} {21, 17, 2, 2, 2, 0}
等等
因此,您选择其中之一,例如 {21, 21, 2, 0, 0, 0}。将其混入您的 6 个属性(A 到 F),例如 {21, 0, 0, 2, 21, 0}。将其映射回您的值 {18, 7, 7, 8, 18, 7}。
注意,洗牌并不像听起来那么容易,这里有关于 stackoverflow 的讨论,还有这篇有趣的文章:http ://www.cigital.com/papers/download/developer_gambling.php
这是正确的(我相信),但不一定有效(或漂亮),C++ 来计算你的集合:
#include <vector>
#include <iterator>
#include <iostream>
typedef std::vector<int> Costs;
typedef std::vector<int> Attrs;
typedef std::vector<Attrs> Choices;
void gen(Choices& c, Attrs a, int sum, Costs costs, int attrs) {
if (sum < 0) { return; }
if (attrs < 1) {
if (sum == 0) {
c.push_back(a);
}
return;
}
auto cc = costs;
for (auto cost : costs) {
a.push_back(cost);
gen(c, a, sum - cost, cc, attrs - 1);
a.pop_back();
cc.erase(cc.begin());
}
}
Choices genChoices(int sum, const Costs& costs, int attrs) {
Choices allChoices;
gen(allChoices, Attrs(), sum, costs, attrs);
return allChoices;
}
int main(int, char*[]) {
const Costs costs { 21, 17, 14, 11, 9, 7, 6, 5, 4, 3, 2, 0 };
const int sum = 44;
const int attrs = 6;
auto choices = genChoices(sum, costs, attrs);
std::cout << choices.size() << "\n";
for (auto c : choices) {
std::copy(std::begin(c), std::end(c), std::ostream_iterator<Attrs::value_type>(std::cout, " "));
std::cout << "\n";
}
return 0;
}
使用 g++ 4.7.3 编译:g++ -std=c++0x -Wall -Wextra attrs.cpp
您给出的示例中有 280 个。