找零钱「Usaco2006 Dec」
题意
FJ要买一个东西,他有\(n\)种货币,每种货币价值为\(v_i\),数量为\(c_i\),而商店老板每种货币都有无限个。求交付硬币数与找零硬币数之和的最小值。
题意
对于FJ,此题拆成01背包跑就可以过了;对于老板,跑完全背包。
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-'),x=-x;
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=101;
const int T=10000;
const int INF=0x3f3f3f3f;
int n,t,ans=INF;
int v[N],c[N];
int f[T*2+1],g[T*2+1];
inline void MAIN () {
read(n),read(t);
for (register int i=1; i<=n; ++i) read(v[i]);
for (register int i=1; i<=n; ++i) read(c[i]);
memset(f,0x3f,sizeof(f)),memset(g,0x3f,sizeof(g));
f[0]=g[0]=0;
for (register int i=1; i<=n; ++i) {
for (register int j=2*T; j>=v[i]; --j) {
for (register int k=1; k<=c[i]; ++k) {
if (k*v[i]>j) break;
f[j]=min(f[j],f[j-k*v[i]]+k);
}
}
}
for (register int i=1; i<=n; ++i) {
for (register int j=v[i]; j<=2*T; ++j) {
g[j]=min(g[j],g[j-v[i]]+1);
}
}
for (register int i=t; i<=T*2; ++i) {
if (f[i]==INF||g[i-t]==INF) continue;
ans=min(ans,f[i]+g[i-t]);
}
if (ans==INF) write(-1);
else write(ans);
}
}
int main () {
Solve::MAIN();
}