这是一个艰难的,至少对于我的最低技能。
基本上,用户将价格列表输入到数组中,然后输入他想要购买的所需项目数,最后不超过最高成本。
我需要检查所需项目数的组合数量是否小于或等于给定的费用。
如果问题是组合中固定数量的项目,比如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++;
}
}
}
}
据我所知,根据用户所需的每个组合的项目数量,没有简单的方法可以灵活调整它。
我非常感谢给予的任何帮助。
答案 0 :(得分:4)
展平嵌套迭代的一个技巧是使用递归。
创建一个函数,该函数包含到目前为止已选择的项目数组,以及到目前为止所拾取的项目数。算法应该是这样的:
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);
答案 1 :(得分:2)
可以使用 backtracking 算法完成此操作。这相当于实现嵌套for loop
的列表。通过尝试查看嵌套for循环序列的执行模式可以更好地理解这一点。
例如,假设您有一个3 for
的序列,并且代码执行已达到第三级(最里面)。在完成所有迭代之后,您将返回到第二级for
,在那里您将进入下一次迭代,在该迭代中您再次跳到第三级for
。类似地,当第二级完成所有迭代时,你跳回到第一级for
,继续下一次迭代,你跳到第二级,然后跳到第三级。
因此,在给定的级别中,您尝试转到更深的一个(如果有的话),如果没有更多的迭代,则返回一个级别(回溯)。
使用回溯,您可以通过数组表示嵌套的for
,其中每个元素都是索引变量:array [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--;
}
}
}