NYOJ 654 喜欢玩warcraft的ltl -- 01背包 一中常数优化

一个常数优化前面的伪代码中有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;
}

你可能感兴趣的:(C++)