ZOJ1366 POJ1276 Cash Machine 经典多重背包问题

来源:互联网 发布:公司域名邮箱收费标准 编辑:程序博客网 时间:2024/06/09 21:55

这是一条非常经典的题,是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 : neosfung@gmail.com * Last modified : 2011-07-18 17:41 * Filename : ZOJ1366 POJ1276 Cash Machine.cpp * Description :http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1366http://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;elsetemp = 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;}