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;
}
posted @ 2012-06-07 20:02  Misty_1  阅读(185)  评论(0编辑  收藏  举报