洛谷 P1833 樱花

洛谷 P1833 樱花

原题链接

Solution

算法:多重背包

但是裸的多重背包复杂度 (O(n*m*p))(p) 为物品个数),过不了此题,会 (TLE)

我们考虑优化。

多重背包有两种优化方法,一种是二进制拆分优化,另一种是单调队列优化

这里只介绍一种:二进制拆分优化多重背包

另一种以后有时间再补吧。

顾名思义,我们要把数进行二进制拆分,那么我们要拆分什么呢?

我们要把物品个数进行差分,例如有 19 个物品,我们要把它拆成 5个物品,每个物品个数分别为1, 2, 4,8,3。

不难证明,这 5 个的任意组合可以表示出 1 ~ 19 的任意一个数,这也是二进制拆分优化的原理。

我们把 19 拆成 5 个物品后,他们的价值和体积也要相应做出改变,即变为 个数 * 单个的价值/体积,跟总价 = 个数 * 单价一个原理。

然后我们直接对拆分后的数组跑一个01背包即可,复杂度 (O(num * m))(num) 为拆分后的数组长度。

完整代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 10010;
int h1, m1, h2, m2, n, m, num;
int t[N], c[N], p[N], w[N * 15], v[N * 15], f[N];

void prework(){			//二进制拆分,可以看着代码理解一下
	for(int i = 1; i <= n; i++){
		int tmp = 1;
		while(p[i]){
			w[++num] = tmp * t[i];
			v[num] = tmp * c[i];
			p[i] -= tmp;
			tmp *= 2;
			if(p[i] < tmp){
				w[++num] = p[i] * t[i];
				v[num] = p[i] * c[i];
				break;
			}
		}
	}
}

int main(){
	scanf("%d:%d %d:%d %d", &h1, &m1, &h2, &m2, &n);
	m = (60 * h2 + m2) - (60 * h1 + m1);
	for(int i = 1; i <= n; i++){
		scanf("%d%d%d", &t[i], &c[i], &p[i]);
		if(!p[i]) p[i] = 1e4;			//赋成无穷大
	}
	prework();
	for(int i = 1; i <= num; i++)		//注意这里是num
		for(int j = m; j >= w[i]; j--)
			f[j] = max(f[j], f[j - w[i]] + v[i]);
	printf("%d
", f[m]);
	return 0;
}

End

本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15115939.html

原文地址:https://www.cnblogs.com/xixike/p/15115939.html