Algorithm 仅使用超过阈值的指定面额硬币可获得的最小货币金额
换句话说,给定一组n个正整数Algorithm 仅使用超过阈值的指定面额硬币可获得的最小货币金额,algorithm,combinations,dynamic-programming,subset-sum,coin-change,Algorithm,Combinations,Dynamic Programming,Subset Sum,Coin Change,换句话说,给定一组n个正整数a和一个阈值B,我想找到最小的C,以便: C>B C=A[1]*k[1]+A[2]*k[2]+…+A[n]*k[n],k[i]是整数>=0 例如,如果A={6,11,16},那么我们可以得到的值是:{0,6,11,12,16,17,18,22,23,24,27,28,29,30,32…所以如果B=14那么C将是16,B=22C=23,B=18C=22 这个问题有以下限制:2
a
和一个阈值B
,我想找到最小的C
,以便:
C>B
,C=A[1]*k[1]+A[2]*k[2]+…+A[n]*k[n]
是整数>=0k[i]
A={6,11,16}
,那么我们可以得到的值是:{0,6,11,12,16,17,18,22,23,24,27,28,29,30,32…
所以如果B=14
那么C
将是16
,B=22
C=23
,B=18
C=22
这个问题有以下限制:2
0
和1
(这就是我被卡住的原因)。您还必须为大小为<1000
的数组B
计算数组C(但这可能无关紧要)。该算法应在C++ 0.3秒以内运行。
这里描述的算法可以解决这个问题,但速度不够快:我计算表格直到B+Amin,因为
Amin*k=B
然后问题不会改变(只需将+1添加到B中),我们可以这样问:如果我们有特定的硬币或钞票(无限多个),并且想用它们购买东西,那么我们可以支付多少钱,以便出纳员必须归还最小的零钱
我怀疑可能有帮助的事情:
如果最大公约数
(x,y)=1
,则任何高于xy的值− x− 可以使用x
和y
获得y
编辑:添加了示例和注释。我认为你无法获得比O(n*B)更好的结果,因为Frobenius数(在这个数之上,所有金额都可以用给定的面额构建)49999和49998比10^9大得多,你至少需要计算一些输入的最佳值。如果gcd(A)>1,则弗罗贝尼乌斯数不存在,但可以通过将所有A和B(向下舍入)除以gcd(A)并将得到的C乘以gcd(A)得到最终结果来防止这种情况 您的伪代码仍有很大的改进空间。您查看所有面额的次数几乎为B+Amin,并且多次将表中的值设置为true 标准实现将如下所示:
sort(A);
table[0] = true;
for (int i = A[0]; i <= B + A[0]; i++)
for (int j = 0; j < n && A[j] <= i; j++)
if (table[i - A[j]]) {
table[i] = true;
break;
}
排序(A);
表[0]=真;
对于(int i=A[0];i您可以计算可以构建的连续金额的数量,如果它比最小的A少一个,您可以立即返回B+1。这个问题似乎确实相当于您链接的硬币问题(对于硬币面额中的一组互质数)。如果Frobenius数为,您也可以通过将所有A除以所有A和B的gcd(向下舍入),将解乘以所有A的gcd得到真实值。这样,您可以确保有一个点可以建立所有金额(无缺口),并且您还可以检查每个金额,如果(B-金额+1)%current A==0表示提前返回。顺便说一句,在您的算法中,一个可能的(不确定会涉及多少开销)优化如下:如果在任何时候您发现表
有Amin
连续的true
元素,那么您可以在这些元素之后构建任何数字(根据维基百科章节中的推理)。还概述了W日志(W)解决方案。
sort(A);
table[0] = true;
for (int i = A[0]; i <= B + A[0]; i++)
for (int j = 0; j < n && A[j] <= i; j++)
if (table[i - A[j]]) {
table[i] = true;
break;
}
table[0] = true;
for (int i = 0; i <= B + Amin; i++)
if (table[i])
for (j = 0; j < n; j++)
if (i + A[j] <= B + Amin)
table[i + A[j]] = true;