bzoj 1716 找零钱

Description

农夫John想到镇上买些补给。为了高效地完成任务,他想使硬币的转手次数最少。即使他交付的硬币数与找零得到的的硬币数最少。 John想要买T(1<=T<=10000)样东西。有N(1<=n<=100)种货币参与流通,面值分别为V1,V2..Vn (1<=Vi<=120)。John有Ci个面值为Vi的硬币(0<=Ci<=10000)。我们假设店主有无限多的硬币,并总按最优方案找零。

Input

* Line 1: 两个整数 N 与 T 。

 * Line 2: N 个数,表示 V1, V2, ..Vn。

* Line 3: N 个数,表示 C1, C2, ..Cn。

Output

* Line 1: 一个整数,表示最优方案的转手次数,如无解输出-1。

Sample Input

3 70
5 25 50
5 2 1

Sample Output

3

 

思路: 问题为多重背包和完全背包的一个结合。 

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define rep(i,a,b) for(R i=a;i<=b;i++)
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--)
 6 #define ms(i,a)    memset(a,i,sizeof(a))
 7 #define gc()       getchar()
 8 template<class T>void read(T &x){
 9   x=0; char c=0;
10   while (!isdigit(c)) c=gc();
11   while (isdigit(c)) x=x*10+(c^48),c=gc();
12 }
13 int const  N=10000+3;
14 int const  M=100+3;
15 int const  inf=1e8;
16 int v[M],c[M],n,m,f[N<<1],g[N<<1];
17 int main(){
18   read(n);read(m);
19   rep(i,1,20000) f[i]=g[i]=inf;
20   rep(i,1,n) read(v[i]);
21   rep(i,1,n) read(c[i]);
22   rep(i,1,n) Rep(j,20000,v[i])  rep(k,1,c[i]) {
23     if(k*v[i]>j) break;
24     f[j]=min(f[j],f[j-k*v[i]]+k);
25   }
26   rep(i,1,n) rep(j,v[i],20000) g[j]=min(g[j],g[j-v[i]]+1);
27   int ans=inf;
28   rep(i,m,20000) if(f[i]!=inf && g[i-m]!=inf) ans=min(ans,f[i]+g[i-m]);
29   if(ans==inf) ans=-1;
30   cout<<ans<<endl;
31   return 0;
32 }
View Code

 

 

 

 
posted @ 2019-01-07 15:41  zjxxcn  阅读(182)  评论(0编辑  收藏  举报