一个常数优化前面的伪代码中有for v=V..1,可以将这个循环的下限进行改进。
由于只需要最后dp[v]的值,倒推前一个物品,其实只要知道dp[v-w[n]]即可。以此类推,对以
第j个背包,其实只需要知道sumc[i->n](第i物品到最后一个物品的消耗和,因为前面的对结果没有影响)即可,即代码中的
1 for i -> 1 to N
2 do for v -> V to 0
3 do
可以改成:
1 for i -> 1 to n
2 do bound -> max(dp[V - sumc[i->n]], c[i]) // 《背包九讲》中这里笔误写错了。
3 for v -> V to bound
4 do
这对于V比较大时是有用的。
----- 摘自《背包问题九讲v1.1》
/*
http://acm.nyist.net/JudgeOnline/problem.php?pid=654
01背包 一中常数优化
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <time.h>
#define CLR(c,v) (memset(c,v,sizeof(c)))
using namespace std;
template <typename _T>
inline _T Max(_T a,_T b){
return (a>b)?(a):(b);
}
template <typename _T>
inline _T Max(_T a,_T b,_T c){
return (a>Max(b,c))?(a):(Max(b,c));
}
const int inf = -(1<<30);
const int INF = (1<<30);
const int COST = 1e6 + 10;
const int M = 1e4 + 10;
int dp[COST];
int v[M];
int c[M];
int main(){
freopen("Input.txt","r",stdin);
freopen("outcheck.txt","w",stdout);
int Ncase;
cin >> Ncase ;
while(Ncase--){
CLR(dp,0);
int max_cost, n_bags,cost ,value;
scanf("%d%d",&n_bags, &max_cost);
for (int i = 1 ; i <= n_bags ; i++){ // max:1000
scanf("%d%d" , &c[i] , &v[i]);
}
for (int i = 1 ; i <= n_bags ; i++){ // max:1000
int sum = 0;
for(int j = i ; j <= n_bags ; j++){
sum += c[j];
}
int bound = Max(max_cost-sum , c[i]);
for(int j = max_cost ; j >= bound ; j--){ // max:100 0000
if( dp[j] < dp[j-c[i]] + v[i]){
dp[j] = dp[j-c[i]] + v[i];
}
}
}
printf("Max experience: %d\n",dp[max_cost]);
}
cout << "pro_time cost:" << (double)clock()/CLOCKS_PER_SEC;
return 0;
}