[英]Given an array, find combinations of n numbers that are less than c
這是一個艱難的,至少我的最低技能。
基本上,用戶將價格列表輸入到陣列中,然后輸入他想要購買的所需數量的項目,最后是不超過的最大成本。
我需要檢查所需數量的項目的組合數量是否小於或等於給定的成本。
如果問題是組合中固定數量的項目,比如3,只需要三個循環選擇每個價格並將它們添加到測試中就會容易得多。
我感到難過的地方是要求用戶輸入任意數量的項目,直到數組中的項目數量。
這是我最初決定的,然后才意識到用戶可以指定任意數字的組合,而不僅僅是三個。 它是在這里的類似主題的幫助下創建的,但同樣只有當用戶指定他想要每個組合3個項目時它才有效。 否則它不起作用。
// test if any combinations of items can be made
for (one = 0; one < (count-2); one++) // count -2 to account for the two other variables
{
for (two = one + 1; two < (count-1); two++) // count -1 to account for the last variable
{
for (three = two + 1; three < count; three++)
{
total = itemCosts[one] + itemCosts[two] + itemCosts[three];
if (total <= funds)
{
// DEBUG printf("\nMatch found! %d + %d + %d, total: %d.", itemCosts[one], itemCosts[two], itemCosts[three], total);
combos++;
}
}
}
}
據我所知,根據用戶所需的每個組合的項目數量,沒有簡單的方法可以使其靈活適應。
我真的很感激任何幫助。
扁平嵌套迭代的一個技巧是使用遞歸。
創建一個函數,該函數包含到目前為止您選擇的項目數組,以及您到目前為止所選擇的項目數。 算法應該是這樣的:
N
的項目數,請計算總和並根據限制進行檢查 為確保您不會選擇相同的項目兩次,請傳遞函數可以選擇的最小索引。 函數的聲明可能如下所示:
int count_combinations(
int itemCosts[]
, size_t costCount
, int pickedItems[]
, size_t pickedCount
, size_t pickedTargetCount
, size_t minIndex
, int funds
) {
if (pickedCount == pickedTargetCount) {
// This is the base case. It has the code similar to
// the "if" statement from your code, but the number of items
// is not fixed.
int sum = 0;
for (size_t i = 0 ; i != pickedCount ; i++) {
sum += pickedItems[i];
}
// The following line will return 0 or 1,
// depending on the result of the comparison.
return sum <= funds;
} else {
// This is the recursive case. It is similar to one of your "for"
// loops, but instead of setting "one", "two", or "three"
// it sets pickedItems[0], pickedItems[1], etc.
int res = 0;
for (size_t i = minIndex ; i != costCount ; i++) {
pickedItems[pickedCount] = itemCosts[i];
res += count_combinations(
itemCosts
, costCount
, pickedItems
, pickedCount+1
, pickedTargetCount
, i+1
, funds
);
}
return res;
}
}
你可以這樣調用這個函數:
int itemCosts[C] = {...}; // The costs
int pickedItems[N]; // No need to initialize this array
int res = count_combinations(itemCosts, C, pickedItems, 0, N, 0, funds);
這可以通過使用回溯算法來完成。 這相當於實現嵌套for loop
列表。 通過嘗試查看嵌套for循環序列的執行模式可以更好地理解這一點。
例如,假設你有一個3 for
s序列,代碼執行已達到第三級(最里面)。 在此之后經過其所有迭代返回到第二個層次for
您去您在其中第三級再跳到下一個迭代,其中for
。 同樣地,當第二級完成其所有的迭代你跳回到第一級for
它繼續與您在其中第二跳級,並從那里在第三下一次迭代。
因此,在給定的級別中,您嘗試轉到更深的一個(如果有的話),如果沒有更多的迭代,則返回一個級別(后退軌道)。
使用回溯您所代表的嵌套for
由陣列,其中每個元素是一個索引變量:數組[0]是用於索引for
0電平,等等。
以下是您的問題的示例實現:
#define NUMBER_OF_OBJECTS 10
#define FORLOOP_DEPTH 4 // This is equivalent with the number of
// of nested fors and in the problem is
// the number of requested objects
#define FORLOOP_ARRAY_INIT -1 // This is a init value for each "forloop" variable
#define true 1
#define false 0
typedef int bool;
int main(void)
{
int object_prices[NUMBER_OF_OBJECTS];
int forLoopsArray[FORLOOP_DEPTH];
bool isLoopVariableValueUsed[NUMBER_OF_OBJECTS];
int forLoopLevel = 0;
for (int i = 0; i < FORLOOP_DEPTH; i++)
{
forLoopsArray[i] = FORLOOP_ARRAY_INIT;
}
for (int i = 0; i < NUMBER_OF_OBJECTS; i++)
{
isLoopVariableValueUsed[i] = false;
}
forLoopLevel = 0; // Start from level zero
while (forLoopLevel >= 0)
{
bool isOkVal = false;
if (forLoopsArray[forLoopLevel] != FORLOOP_ARRAY_INIT)
{
// We'll mark the loopvariable value from the last iterration unused
// since we'll use a new one (in this iterration)
isLoopVariableValueUsed[forLoopsArray[forLoopLevel]] = false;
}
/* All iterations (in all levels) start basically from zero
* Because of that here I check that the loop variable for this level
* is different than the previous ones or try the next value otherwise
*/
while ( isOkVal == false
&& forLoopsArray[forLoopLevel] < (NUMBER_OF_OBJECTS - 1))
{
forLoopsArray[forLoopLevel]++; // Try a new value
if (loopVariableValueUsed[forLoopsArray[forLoopLevel]] == false)
{
objectUsed[forLoopsArray[forLoopLevel]] = true;
isOkVal = true;
}
}
if (isOkVal == true) // Have we found in this level an different item?
{
if (forLoopLevel == FORLOOP_DEPTH - 1) // Is it the innermost?
{
/* Here is the innermost level where you can test
* if the sum of all selected items is smaller than
* the target
*/
}
else // Nope, go a level deeper
{
forLoopLevel++;
}
}
else // We've run out of values in this level, go back
{
forLoopsArray[forLoopLevel] = FORLOOP_ARRAY_INIT;
forLoopLevel--;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.