0w1

POJ 3260 The Fewest Coins ( Knapsack multiple & complete DP )

3260 -- The Fewest Coins
n ≤ 100 types of currency exists, each value v[i] ≤ 120, and I have c[i] ≤ 100 of them. Answer the minimum sum of coins that I have to give and take, when I am to buy a product of T ≤ 10000 dollars.
This is basically a problem of both complete knapsack and multiple knapsack combined. However, it is a little tricky to decide the maximum bound of the number of coins that we should give. Although t * 2 seems to be enough, but actually the tight bound is maxv * maxv. I saw it from this article
背包问题--POJ 3260 The Fewest Coins【完全背包+多重背包】 - AndreMouche - 博客园
proved by Pigeonhole principle - Wikipedia, the free encyclopedia.

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXT = 1e4 + 4;
const int MAXN = 100 + 2;
const int MAXV = 120 + 1;
const int MAXC = 1e4 + 4;
const int INF = 1e9;

int n, t;
int v[MAXN], c[MAXN];
int maxv;
int mtot[MAXT + MAXV * MAXV], mmul[MAXT + MAXV * MAXV];

void upmin(int &a, int b){ a = min( a, b ); }

void dp_total(int n, int lim){
    fill( mtot, mtot + lim + 1, INF );
    mtot[0] = 0;
    for(int i = 0; i < n; ++i)
        for(int j = 0; j + v[i] <= lim; ++j)
            upmin( mtot[ j + v[i] ], mtot[j] + 1 );
}

void dp_multi(int n, int lim){
    fill( mmul, mmul + lim + 1, INF );
    mmul[0] = 0;
    for(int i = 0; i < n; ++i){
        int num = c[i];
        for(int k = 1; num > 0; k <<= 1){ // binary enumeration
            int mul = min( k, num );
            for(int j = lim - v[i] * mul; j >= 0; --j)
                upmin( mmul[ j + v[i] * mul ], mmul[j] + mul );
            num -= mul;
        }
    }
}

void solve(){
    dp_total( n, maxv * maxv );
    dp_multi( n, t + maxv * maxv );
    int ans = INF;
    for(int i = maxv * maxv; i >= 0; --i)
        upmin( ans, mtot[i] + mmul[t + i] );
    if( ans == INF ) puts("-1");
    else printf("%d\n", ans);
}

int main(){
    scanf("%d %d", &n, &t);
    for(int i = 0; i < n; ++i){
        scanf("%d", &v[i]);
        maxv = max( maxv, v[i] );
    }
    for(int i = 0; i < n; ++i)
        scanf("%d", &c[i]);
    solve();
    return 0;
}