链接:点击打开链接
题意:顾客去买T元的物品,有N种钱币,给出每种钱币的面额和数量,卖家每种钱币有无限个.现在顾客想让交易的钱张数最少(即找回和付出钱的张数总和最少)
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
bool f[10150];
int dp1[10150],dp2[10150];
int v[105],w[105];
int main(){
int n,m,i,j,k,ans,num,tmp;
while(scanf("%d%d",&n,&m)!=EOF){ //顾客手中每种钱币数量是有限的,而卖家
memset(f,0,sizeof(f)); //每种钱币的数量是无限的,因此可以看出
memset(dp1,INF,sizeof(dp1)); //顾客是多重背包,卖家是完全背包
memset(dp2,INF,sizeof(dp2)); //这个问题的关键是背包的上限,我个人理
for(i=0;i<n;i++) //上限因该是T+120,因为卖家每种钱都是无
scanf("%d",&v[i]); //限的,因此多出的这个值的任何钱卖家都可
for(i=0;i<n;i++) //以原封不动的找回去,所以上限是T+120
scanf("%d",&w[i]);
f[0]=1,dp1[0]=0,dp2[0]=0;
for(i=0;i<n;i++){
num=w[i];
for(k=1;num>0;k<<=1){
tmp=min(k,num);
for(j=10149;j>=v[i]*tmp;j--)
dp1[j]=min(dp1[j],dp1[j-v[i]*tmp]+tmp);
num-=tmp; //求出每种钱数所需的最少张数
}
} //多重背包
for(i=0;i<n;i++)
for(j=v[i];j<10150;j++) //求出卖家找钱的每种钱数的最少张数
dp2[j]=min(dp2[j],dp2[j-v[i]]+1); //我感觉这个范围可以更小一点,但是
ans=INF; //还是防止出现问题,因此与上面同一
for(i=m;i<10150;i++)
if(dp1[i]!=INF&&dp2[i-m]!=INF)
ans=min(ans,dp1[i]+dp2[i-m]);
if(ans==INF) //找出和的最小值
puts("-1");
else
printf("%d\n",ans);
}
return 0;
}