1. 程式人生 > 實用技巧 >[POI2005]Bank notes 題解

[POI2005]Bank notes 題解

【題目大意】

Byteotian Bit Bank (BBB) 擁有一套先進的貨幣系統,這個系統一共有\(n\)種面值的硬幣,面值分別為\(b1, b2,..., bn\). 但是每種硬幣有數量限制,現在我們想要湊出面值\(k\)求最少要用多少個硬幣.

\(n\le200,1\le k,b_i \le100000\)

【分析】

看一眼題目,一道多重揹包的模板題,但是資料範圍比較大,如果直接寫多重揹包則會TLE

【優化】

考慮採用二進位制進行優化

【程式碼】

#include <bits/stdc++.h>
using namespace std ;
const int MAXN = 1000000 + 5 ;
int n , k ;
int b[ MAXN ] ;
int f[ MAXN ] , w[ MAXN ] , c[ MAXN ] ;
inline void solve ( int wi , int ci , int numi ) { // 二進位制拆分
    int t = 1 ;
    while ( numi >= t ) {
        w[ ++ w[ 0 ] ] = wi * t ;
        c[ ++ c[ 0 ] ] = t ;
        numi -= t ;
        t <<= 1 ;
    }
    w[ ++ w[ 0 ] ] = wi * numi ;
    c[ ++ c[ 0 ] ] = numi ;
}
signed main () {
    scanf ( "%d" , &n ) ;
    for ( int i = 1 ; i <= n ; i ++ )
        scanf ( "%d" , &b[ i ] ) ;
    for ( int i = 1 ; i <= n ; i ++ ) {
        int num ; scanf ( "%d" , &num ) ;
        solve ( b[ i ] , 1 , num ) ;
    }
    memset ( f , 0x3f , sizeof ( f ) ) ; n = w[ 0 ] ;
    scanf ( "%d" , &k ) ;
    f[ 0 ] = 0 ;
    for ( int i = 1 ; i <= n ; i ++ ) {
        for ( int j = k ; j >= w[ i ] ; j -- ) {
            f[ j ] = min ( f[ j ] , f[ j - w[ i ] ] + c[ i ] ) ;
        }
    }
    printf ( "%d\n" , f[ k ] ) ;
    return 0 ;
}