动态规划算法:硬币的最大总和(小于或等于k)
Posted
技术标签:
【中文标题】动态规划算法:硬币的最大总和(小于或等于k)【英文标题】:Dynamic Programming Algorithm: Maximum sum of coins (less or equal to k) 【发布时间】:2015-02-04 15:52:13 【问题描述】:给定一个包含 n 个硬币值的列表和一个总和 k,找到小于或等于 k 的最大可能总和。每个硬币可以根据需要多次使用。如果没有选择硬币,0 被认为是最大的。 我尝试解决这个问题,我知道这是动态编程,但我无法在小于 O(n^2) 的时间内解决这个问题。 这个问题的算法是什么?
【问题讨论】:
我认为您可以使用相同的coin change
算法。但这将是 O(nk)
除非 P=NP(很可能是 P!=NP),否则您无法在 O(n^2) 中解决它,因为这是子集和问题,即 NP Complete。整数的 DP 解决方案提供伪多项式 O(nk)
尝试将问题定义为“让我们将 f(___) 定义为遵守限制 ___ 的最大可能总和”。你可以用什么来代替___s? (这里的两个 ___ 可能不同。)
@amit:有关系,但真的一样吗?很容易将这个问题转换为子集和——只需添加每个硬币 i 的 RoundUp(k/value[i]) 副本——但如何朝另一个方向发展并不明显,即如何表示一个 finite 在这个问题中的子集和问题中某个数的副本数。
@j_random_hacker Given a list of n coin values and a sum k, find the maximum possible sum which is less or equal to k.
这正是子集和的优化问题。细微的区别是您可以多次选择每个元素,这不会使问题变得更容易/更难。
【参考方案1】:
除非 P=NP(很可能是 P!=NP),否则您无法在 O(n^2) 中解决它,因为这是subset sum problem,即NP Complete。 DP solution for integers offers psedo-polynomialO(nk)
时间,这可能是你最好的选择。
在您的情况下,您可以多次选择一个元素,因此递归公式将是:
D(0,i) = true
D(x,0) = false x!=0
D(x,i) = D(x-coin[i],i) OR D(x,i-1)
^
note i and not (i-1) here
您需要找到小于k
的最高x
使得D(x,n) = true
,这相当容易 - 如果您构建一个大小为 (k+1)*(n+1) 的二维表 - 您需要找到最右边的列(让它成为x
),这样D[x][n] = true
,在最后一行的单个路径中很容易找到。
【讨论】:
第一个问题:D(x,i) 是否代表语句的真假值:可以从 i 个硬币中得到 sum x 吗? @user3245855 D(x,i) 表示语句的真假值:可以用硬币求和x吗c1,c2,...,ci
【参考方案2】:
#include<iostream>
#include<stdlib.h>
#define INT_MAX 99999999
using namespace std;
int compare(const void *a,const void *b)
return *(int*)a-*(int*)b;
struct res
bool yes;
int count;
;
struct res *t=new struct res [2000001];
//t=new struct res [1000001];
int fun(int arr[],int n,int k)
int max=arr[n-1]*k;
t[0].yes=true;
t[0].count=0;
int f;
for(int i=1;i<max;i++)
t[i].yes=false;
t[i].count=INT_MAX;
for(int j=0;j<n;j++)
int val=arr[j];
int cnt=1;
f=0;
while(val<=i && cnt<=k)
if(t[i-val].yes==true)
t[i].yes=true;
t[i].count=min(t[i].count,cnt+t[i-val].count);
break;
val+=arr[i];
cnt++;
for(int i=1;i<max;i++)
if(t[i].count>k)
return i-1;
int main()
int t,k,n;
int arr[50];
cin>>t;
int x=1;
while(t--)
cin>>k>>n;
for(int i=0;i<n;i++)
cin>>arr[i];
qsort(arr,n,sizeof(int),compare);
cout<<"Case #"<<x<<endl<<fun(arr,n,k)<<endl;
x++;
【讨论】:
任何解释都会有所帮助。以上是关于动态规划算法:硬币的最大总和(小于或等于k)的主要内容,如果未能解决你的问题,请参考以下文章