回答
如您在評論中提到的那樣,10是問題中的最高數字(也是最大元素數量)。然後蠻力(用聰明bitmasking,見this tutorial)會做:
// N is the number of elements and arr is the array.
for (int i = 0; i < (1 << N); ++i) {
int sum = 0;
for (int j = 0; j < N; ++j) if (i & (1 << j)) sum += arr[j];
if (sum == required_sum); // Do something with the subset represented by i.
}
該算法複雜度爲O(N * 2^N)。注意,代碼是正確的,只要N < 32.注意,具有一定和的子集的數目可以是指數的(大於2 ^(N/2))。例如,{1,1,1,1,...,1}和sum = N/2。
然而,如果N較大,但N * required_sum不是非常大(高達數百萬),可以使用下面的復發(用動態編程或記憶化):
f(0, 0) = 1
f(0, n) = 0 where n > 0
f(k, n) = 0 where k < 0
f(k + 1, S) = f(k, S - arr[k]) + f(k, S) where k >= 0
其中f(K ,S)表示用元素0..k的子集獲得總和S的可能性。動態編程表可用於生成所有子集。生成表的運行時間是O(N * S),其中S是所需的總和。從表中生成子集的運行時間與這些子集的數量成比例(可能非常大)。
有關該問題的一般注意事項:
的問題一般是NP-Complete。因此,它沒有已知的多項式時間算法。它確實有一個pseudo-polynomial time algorithm,即上面的重現。
「最好」的方式取決於你正在優化什麼是最好的方式。
如果不存在陣列中的許多元件,有一個簡單的組合學算法:對於從1到n
所有長度(其中n
是數組中元素的數目),檢查n
數目的所有可能集合並打印各總和爲15。
從時間到實施的角度來看,這可能是最好的。從運行效率的角度來看,動態編程解決方案(這是一個DP問題)可能是最好的;這裏的DP解決方案是O(N³)
,其中組合解決方案遠不止於此。
DP算法的要點(我沒有編寫代碼)是通過你的數組,並跟蹤所有可能的和你可以看到的子數組的總和。當你到達每一個新的數組元素時,通過你以前得到的所有部分和,並將它添加到它們(而不是刪除原始部分和)。每當有東西擊中15或通過它時,從你正在跟蹤的集合中丟棄該總和(如果它打到15則打印它)。
我的建議是去遞歸。
跟蹤的baseindex和CURRENTINDEX 並嘗試累積值每次遞歸
回報CURRENTINDEX的整數值,當累積值是15 否則如果CURRENTINDEX達到5,並且累計值是不是15返回0
當返回值爲0且baseindex仍小於5時,則將基址索引加1並重置當前索引和累加值,並再次開始遞歸。
遞歸是我能想到的一個選項。因爲我有一些閒暇時間在我手上,所以我把這個功能放在一起(儘管它可能不必要的大,而且沒有被優化到極限)。我只用你提供的號碼進行測試。
void getCombinations(std::vector<int>& _list, std::vector<std::vector<int>>& _output,
std::vector<int>& _cSumList = std::vector<int>(), int _sum = 0)
{
for (std::vector<int>::iterator _it = _list.begin(); _it < _list.end(); ++_it)
{
_sum += *_it;
_cSumList.push_back(*_it);
std::vector<int> _newList;
for (std::vector<int>::iterator _itn = _list.begin(); _itn < _list.end(); ++_itn)
if (*_itn != *_it)
_newList.push_back(*_itn);
if (_sum < 15)
getCombinations(_newList, _output, _cSumList, _sum);
else if (_sum == 15)
{
bool _t = false;
for (std::vector<std::vector<int>>::iterator _itCOutputList = _output.begin(); _itCOutputList < _output.end(); ++_itCOutputList)
{
unsigned _count = 0;
for (std::vector<int>::iterator _ita = _itCOutputList->begin(); _ita < _itCOutputList->end(); ++_ita)
for (std::vector<int>::iterator _itb = _cSumList.begin(); _itb < _cSumList.end(); ++_itb)
if (*_itb == *_ita)
++_count;
if (_count == _cSumList.size())
_t = true;
}
if (_t == false)
_output.push_back(_cSumList);
}
_cSumList.pop_back();
_sum -= *_it;
}
}
用法示例與你的號碼:
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<int> list;
list.push_back(7);
list.push_back(8);
list.push_back(10);
list.push_back(5);
list.push_back(3);
std::vector<std::vector<int>> output;
getCombinations(list, output);
for (std::vector<std::vector<int>>::iterator _it = output.begin(); _it < output.end(); ++_it)
{
for (std::vector<int>::iterator _it2 = (*_it).begin(); _it2 < (*_it).end(); ++_it2)
std::cout << *(_it2) << ",";
std::cout << "\n";
}
std::cin.get();
return 0;
}
最好的辦法是主觀的。正如我所說,上面的代碼可以大大改善,但應該給你一個出發點。
排序元素的數組。 維護兩個指針,一個在排序數組的開始處,另一個在結尾處。 如果兩個元素的總和大於15,則減少第二個指針。 如果總和小於15,則增加第1個指針。 如果sum等於15,則記錄這兩個元素,並增加第一個指針。
希望它有效。
- 1. Java,與數組的組合算法
- 2. 組合算法
- 3. 算法組合
- 4. 數字組合算法
- 5. 分組組合算法
- 6. 在一個合併多個數組的算法
- 7. 一個數組中的多個組合
- 8. 合成一組二維點的算法
- 9. C#中的組合算法
- 10. Java的組合算法
- 11. Python中的組合算法
- 12. 組合算法返回一個號碼的所有可能的組合物
- 13. 組合多個加密算法的
- 14. 寫更快的組合數學算法
- 15. 動態合併數組的算法
- 16. 運行整數數組的所有組合的算法
- 17. 計算唯一的組合
- 18. 給定一個數組嵌套算法
- 19. 拿一個數組並將它組合成另一個數組
- 20. 組合算法:一(s)和零(s)
- 21. 深度第一組合算法
- 22. 計算大數的組合
- 23. 組合算法挑戰
- 24. 算法有序組合
- 25. 算法找出cheapst組合
- 26. 所有組合樹算法
- 27. 算法循環組合
- 28. C#有序組合算法
- 29. 數組排序 - 和合並 - 算法
- 30. 組合3個更多值組的算法
數組中的整數範圍是多少? – Deepak 2012-02-19 05:58:57
儘管可能不直接回答你的問題,但閱讀[整數分區](http://en.wikipedia.org/wiki/Partition_(number_theory))可能會很有趣。 – 2012-02-19 06:01:41
10是最高的東西將是 – 2012-02-19 06:02:14