最好的解释方法就是使用一个例子:
您正在以2000美元的价格参观一家商店,您的目标是在旅行结束时获得0美元。 你不知道有多少物品可用,也不知道它们的价格是多少。
假设目前有3件商品价格为1000美元,750美元,500美元。 (重点是计算所有可能的解决方案,而不是最有效的解决方案。)
你可以花2000美元,这意味着:
You can buy the $1000 item 0, 1 or 2 times.
You can buy the $750 item 0, 1 or 2 times.
You can buy the $500 item 0, 1, 2, 3 or 4 times.
最后我需要能够拥有所有解决方案,在这种情况下它将是
2*$1000
1*$1000 and 2*$500
2*$750 and 1*$500
4*$500
旁注:你不能有一个重复的解决方案(像这样)
1*$1000 and 2*$500
2*$500 and 1*$1000
这就是我的尝试:
首先使用
调用此函数 goalmoney = convert.ToInt32(goalMoneyTextBox.Text);
totalmoney = Convert.ToInt32(totalMoneyTextBox.Text);
int[] list = new int[usingListBox.Items.Count];
Calculate(0, currentmoney, list);
功能:
public void Calculate(int level, int money, int[] list)
{
string item = usingListBox.Items[level].ToString();
int cost = ItemDict[item];
for (int i = 0; i <= (totalmoney / cost); i++)
{
int[] templist = list;
int tempmoney = money - (cost * i);
templist[level] = i;
if (tempmoney == goalmoney)
{
resultsFound++;
}
if (level < usingListBox.Items.Count - 1 && tempmoney != goalmoney) Calculate(level + 1, tempmoney, templist);
}
}
答案 0 :(得分:2)
您的问题可以简化为一个众所周知的标记为Frobenius equation的数学问题,该问题与众所周知的Coin problem密切相关。假设您有N
项,其中第i项费用为c[i]
,您需要花费S
$。所以你需要找到方程
c[1]*n[1] + c[2]*n[2] + ... + c[N]*n[N] = S
其中所有n[i]
都是未知变量,每个n[i]
是第i种类型的已购买项目数。
该等式可以以各种方式解决。以下函数allSolutions
(我想它可以另外简化)找到给定方程的所有解:
public static List<int[]> allSolutions(int[] system, int total) {
ArrayList<int[]> all = new ArrayList<>();
int[] solution = new int[system.length];//initialized by zeros
int pointer = system.length - 1, temp;
out:
while (true) {
do { //the following loop can be optimized by calculation of remainder
++solution[pointer];
} while ((temp = total(system, solution)) < total);
if (temp == total && pointer != 0)
all.add(solution.clone());
do {
if (pointer == 0) {
if (temp == total) //not lose the last solution!
all.add(solution.clone());
break out;
}
for (int i = pointer; i < system.length; ++i)
solution[i] = 0;
++solution[--pointer];
} while ((temp = total(system, solution)) > total);
pointer = system.length - 1;
if (temp == total)
all.add(solution.clone());
}
return all;
}
public static int total(int[] system, int[] solution) {
int total = 0;
for (int i = 0; i < system.length; ++i)
total += system[i] * solution[i];
return total;
}
在上面的代码system
中,系数c[i]
和total
的数组是S
。有一个明显的限制:system
应该没有任何零元素(这导致无限数量的解决方案)。稍微修改上述代码可避免此限制。
答案 1 :(得分:0)
假设您有一个类Product
,它公开了一个名为Price
的属性,这是一种方法:
public List<List<Product>> GetAffordableCombinations(double availableMoney, List<Product> availableProducts)
{
List<Product> sortedProducts = availableProducts.OrderByDescending(p => p.Price).ToList();
//we have to cycle through the list multiple times while keeping track of the current
//position in each subsequent cycle. we're using a list of integers to save these positions
List<int> layerPointer = new List<int>();
layerPointer.Add(0);
int currentLayer = 0;
List<List<Product>> affordableCombinations = new List<List<Product>>();
List<Product> tempList = new List<Product>();
//when we went through all product on the top layer, we're done
while (layerPointer[0] < sortedProducts.Count)
{
//take the product in the current position on the current layer
var currentProduct = sortedProducts[layerPointer[currentLayer]];
var currentSum = tempList.Sum(p => p.Price);
if ((currentSum + currentProduct.Price) <= availableMoney)
{
//if the sum doesn't exeed our maximum we add that prod to a temp list
tempList.Add(currentProduct);
//then we advance to the next layer
currentLayer++;
//if it doesn't exist, we create it and set the 'start product' on that layer
//to the current product of the current layer
if (currentLayer >= layerPointer.Count)
layerPointer.Add(layerPointer[currentLayer - 1]);
}
else
{
//if the sum would exeed our maximum we move to the next prod on the current layer
layerPointer[currentLayer]++;
if (layerPointer[currentLayer] >= sortedProducts.Count)
{
//if we've reached the end of the list on the current layer,
//there are no more cheaper products to add, and this cycle is complete
//so we add the list we have so far to the possible combinations
affordableCombinations.Add(tempList);
tempList = new List<Product>();
//move to the next product on the top layer
layerPointer[0]++;
currentLayer = 0;
//set the current products on each subsequent layer to the current of the top layer
for (int i = 1; i < layerPointer.Count; i++)
{
layerPointer[i] = layerPointer[0];
}
}
}
}
return affordableCombinations;
}