poj 1276 Cash Machine(多重背包问题)
最近在学习背包九讲,呃,现在刚看到多重背包问题,还是有点慢啊。
这题是典型的多重背包问题,题意是,给你n中面值不同的纸币,每种面值为c,每种有n[i]张,给你一定的数额,问有这些纸币能组合出小于等于所给面值的最大钱数。
但是题目中给的数据范围有点大,如果按基本的多重背包来做会TLE,看了《背包九讲》中利用二进制思想的优化,没看懂伪代码,搜了个代码慢慢研究,终于有点明白了,不过还是不明白为什么要按1 , 2, 4, ……2^(k-1) , n - 2^k 这样确定系数,呃,还是慢慢想吧~~
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #define maxm 102 #define maxn 100005 using namespace std ; int val[maxm] , dp[maxn] ; int main() { int count , i , j , v , c , n , cash ; while ( scanf ( "%d%d" , &cash , &n ) != EOF ) { count = 0 ; for ( i = 0 ; i < n ; i++ ) { scanf ( "%d%d" , &v , &c ); int k = 1; while ( v - k >= 0 )//利用二进制思想拆分 { val[count++] = k * c; v -= k ; k *= 2 ; } if ( v ) val[count++] = v * c ; } memset( dp , 0 , sizeof( dp ));//初始化 dp[0] = 1 ;//能组成的最小的面值为0 , 所以0初始化为1 for ( i = 0 ; i < count ; i++ )//0-1背包 { for ( j = cash ; j >= val[i] ; j-- ) if ( dp[j - val[i]] ) dp[j] = 1 ; } int k = cash ; while ( !dp[k] ) k--; printf ( "%d\n" , k ); } return 0; }