- 这是竞争对手程序员手册中的一个问题:*
我们得到了k
个产品在n
天内的价格,并且我们希望每种产品只购买一次。但是,我们被允许在一天内最多购买一件产品。最低总价是多少?
| 0个|一个|二个|三个|四个|五个|六个|七个| 7 |
| --|--|--|--|--|--|--|--| ------------ |
| 六个|九个|五个|二| 八个|九个|一个|六个| 6 |
| 八个|二| 六个|二个|七个|五个|七个|二个| 2 |
| 五个|三个|九个|七个|三个|五个|一人| 四个| 4 |
最佳选择是:
- 产品0在第3天价格为2,
- 产品1在第1天价格为2,
- 产品2在第6天的价格为1。
总共是5个。
解决方案:
我们要么在d
日不购买任何产品,要么购买属于集合S
的x
产品。在后一种情况下,我们从集合S
中删除x
,并将x
的价格添加到总价格中。
下面是本书中的代码:
#include <stdio.h>
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
int main()
{
int price[3][8] = {{ 6, 9, 5, 2, 8, 9, 1, 6 },
{ 8, 2, 6, 2, 7, 5, 7, 2 },
{ 5, 3, 9, 7, 3, 5, 1, 4 }};
int n = 8, k = 3;
int total[1<<10][10];
//Buy all products on day 0
for (int x = 0; x < k; x++) {
total[1<<x][0] = price[x][0];
}
for (int d = 1; d < n; d++) {
for (int s = 0; s < (1<<k); s++) {
total[s][d] = total[s][d-1];
for (int x = 0; x < k; x++) {
if (s & (1<<x)) {
total[s][d] = min(total[s][d], total[s ^ (1<<x)][d-1] + price[x][d]);
break;
}
}
}
}
//Output
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
printf("%d", total[i][j]);
}
printf("\n");
}
}
字符串
这个问题限制了我们每天只买一种产品,但代码似乎根本没有解决这个问题(而且,我们在第一天买所有产品,这很好)。该产量正好是在该日可获得的每种产品的最小值[1,2,1]。我做错什么了?
4条答案
按热度按时间vngu2lb81#
经过相当长的时间在调试器中,我能够使算法从书中的工作。可以说书中提供的片段完全被打破了。
最主要的编辑:
1.如果我们从 * 相邻 * 和更新更复杂的和,则我们将仅更新更复杂的和,也就是说,我们不从001或010的和更新111处的和。我们使用__builtin_popcount来查找当前设置的索引与我们试图更新的索引之间的差异。
1.我们将只更新更高的顺序集,如果足够的天已经过去了 * 前 * 集被填充。
我希望我没有在这里(再次)犯错误。如果我做了,请随时纠正我。这次我确实试着验证了多个输入,这似乎起作用了。
请注意,我使用了多个完全不必要的局部变量。我只是想要一些清晰度和可读性。
这本质上与书中的算法相同,但有一组必要的限制使其正确运行。如果没有这些限制,它会添加完全不兼容的东西,或者在错误的时间添加,最终无法工作。
算法确实解决了你在
sol[xorIndex][dayIndex-1] + currentPrice
部分每天只能购买1件商品的问题。被访问的sol部分在 * 前 * 天用项目 * 填充,* 不包括 * 我们正在添加的项目。字符串
zxlwwiss2#
发布的算法具有n.k.2k的时间和空间复杂度,这似乎非常昂贵,并且可能导致堆栈溢出对于中等大小的集合。
此外,输出不是很有信息性,并且限制 * 每天最多一个产品 * 似乎无法执行。
下面是一个使用递归的替代方法,具有类似的时间复杂度nk,但内存占用要小得多:
字符串
输出:
price: 5, days: [ 3 1 6 ]
aor9mmx13#
原来书中提供的解决方案是不完整的。为了使程序返回正确的结果,必须填充第一天的所有子集,但在书中,只有包含Map到2的幂的单个元素的子集,即索引
1,2,4,etc of total[][]
被填充,这使得其他子集具有0
的值。这使得随后的每一天的计算取最小值,即0
。line 14 to 16
中的代码字符串
必须替换为:
型
每天的最小总和将是包含所有元素的集合,即
total[(1<<k)-1][index of day]
。经过所有更改后,工作代码为:型
bkhjykvo4#
这是正确答案
替换第一个代码块
字符串
由
型
并从书中提到的以下代码块中删除 break 条件。