链接:点击打开链接
题意:顾客去买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; }