您的位置:首页 > 其它

poj3260(多重背包+完全背包)

2016-02-23 22:23 169 查看
链接:点击打开链接

题意:顾客去买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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: