这是一条非常经典的题,是0/1背包问题的变种,详细可以看看《背包9讲-多重背包问题》。简单说一下,对于n1 D1 n2 D2 ... nN DN,n为D的数量,则可以把n分解为k1=1,k2=2,k3=4,k4=8...km,且k1+k2+...km=n,其中k1,k2...km-1为2的幂,km不一定是2的幂。这个要表达清楚是很困难的,你们可以看一下《背包9讲》。同时背包问题有两种不同的问法,即恰好装满背包和不要求装满背包,大家可以看一下以下这段解释。
以下摘自《背包9讲》
我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。 如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。 为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。 这个小技巧完全可以推广到其它类型的背包问题,后面也就不再对进行状态转移之前的初始化进行讲解。
代码如下
/******************************************************************************* * Author : Neo Fung * Email : [email protected] * Last modified : 2011-07-18 17:41 * Filename : ZOJ1366 POJ1276 Cash Machine.cpp * Description : http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1366 http://poj.org/problem?id=1276 * *****************************************************************************/ // ZOJ1366 POJ1276 Cash Machine.cpp : Defines the entry point for the console application. // // #include "stdafx.h" #include <fstream> #include <stdio.h> #include <iostream> #include <string.h> #include <string> #include <vector> #include <stack> #include <deque> #include <map> #include <math.h> #include <algorithm> #include <numeric> #include <functional> #include <memory.h> using namespace std; int main(void) { // ifstream cin("data.txt"); int cash,N; int n,D; int temp; vector<int> cashVec; int *DP=new int[100001]; int power[]={1,2,4,8,16,32,64,128,256,512}; while(cin>>cash>>N) { for (int i=0;i<=cash;++i) { DP[i]=0; } DP[0]=0; cashVec.clear(); cashVec.push_back(0); for(int i=1;i<=N;++i) { cin>>n>>D; if(!n) temp=0; else temp = log((n+1)*1.0) / log(2.0) + 0.99999999; for(int j=0;j<temp;++j) { if(n>power[j]) { cashVec.push_back(D*power[j]); n -=power[j]; } else { cashVec.push_back(n*D); } } } if(cash == 0 || N==0) { cout<<0<<endl; continue; } for(int i=1;i<cashVec.size();++i) if (cash < cashVec.at(i)) { continue; } else { for(int j=cash;j>= cashVec.at(i);--j) { // if(j<=cashVec.at(i)) DP[j] = max(DP[j],DP[j-cashVec.at(i)]+cashVec.at(i)); } } cout<<DP[cash]<<endl; } cashVec.clear(); delete []DP; return 0; }