背包问题
卖方:这件商品14元
买方:给你20元
卖方:不好意思,我的零钱不够
买方:好吧,这是15元,剩的当小费
当到一个地方旅游时,如果你买东西的地方不支持信用,带零钱还是非常有用的。特别是有时候卖方没有零钱,如果你没有刚好的钱,你需要支付比卖价多一点。
当然你想付尽量少的钱(至少是商品价值的钱)。并且,当支付最少钱的时候,也最好是支付的硬币的数量最少。
Input
第一行包含一个整数表示测试数据的组数。每组测试数据每一行包含一个整数,表示你需要付的钱数,钱数不超过10000元。接下来包含一个整数n,表示你所拥有的钱的数量,n最多是100,接下来的n行每行一个整数,表示你有的每个硬币的面值,注意钱的面值可以是任意的,不和我们现在用的面值一样,钱的面值不超过10000元。
Output
对每组测试数据,在一行上输出两个整数:需要支付的钱数和数量。
Sample Input
1
1400
3
500
1000
2000
Sample Output
1500 2
j代表从1到所有钱数的和,为了简便存储,赋予j特定的范围30400,a[i]的值表示拥有钱的面值,dp[i][j]的值表示前 i 张钱刚好能支付对应的钱为 j 时所需要的钱的张数
初始赋值:将dp[i][i]整个表赋值为比输入的钱数大1的值(n+1),dp[i][0]=0,
关键算法:如果j<a[i] dp[i][j]=dp[i-1][j]
如果 j>=a[i] dp[i][j]=min(dp[i-1][j-a[i]]+1,dp[i-1][j])
查找用到的钱的面值:将需要支付的钱数m作为搜寻dp表的初始 j 值,从dp[i][m]开始正向搜索,从左到右、从上到下查找到第一个比(n+1)小的值输出其dp[i][j]的值表示钱的数量,j表示支付的钱数。
#include <iostream>
#include <algorithm>
using namespace std;
int dp[101][30400];
int main()
{
int x,m,n,a[101],sum;
cin>>x;
while(x--)
{
cin>>m;
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
for(int i=0; i<=n; i++)
for(int j=0; j<=30400; j++)
dp[i][j]=n+1;
for(int i=0; i<=n; i++)
dp[i][0]=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=30400; j++)
{
if(j<a[i])
dp[i][j]=dp[i-1][j];
if(j>=a[i])
dp[i][j]=min(dp[i-1][j-a[i]]+1,dp[i-1][j]);
}
int tp=0,mp=0;
for(int j=m; j<=30400; j++)
{
for(int i=1; i<=n; i++)
{
if(dp[mp][j]>dp[i][j])
{
mp=i;
tp=j;
}
}
if(tp!=0)
{
cout<<tp<<" "<<dp[mp][tp]<<endl;
break;
}
}
}
return 0;
}