「CEOI2018」Cloud computing DP题解

题目描述

Johnny 成立了 Bytecomp,一个提供云计算能力的公司。这样的公司通常拥有许多快速计算机,客户可以在其上进行计算。

但是 Johnny 还没有购买任何计算机。于是他前往一家计算机商店,收到了包含全部 n n n 台可用的计算机的清单。
每台计算机都可以用三个属性描述:处理器的核心数量 c i c_i ci,时钟频率 f i f_i fi 以及价格 c i c_i ci。每台计算机包含 c i c_i ci 个不会互相干扰的核心,所以它们可以被分配给不同的任务。

当客户订购资源时,她会指定所需的核心数 C j C_j Cj 以及所需的最低时钟频率 F j F_j Fj,订单还包含客户愿意支付的价格 V j V_j Vj
如果接受了一份订单,Bytecomp 需要提供对客户所需的算力的专用访问权。Johnny 需要选择 C i C_i Ci 个核心(可能来自不同的计算机),且它们的时钟频率至少为 F j F_j Fj,这些核心不能被分配给其它订单。

请你帮助 Johnny 赚取尽可能多的利润:接受一部分客户订单,并购买商店中的一部分计算机,以满足所有接受了的订单的需求。
你的目标是最大化总利润,即为客户提供算力的收入与购买计算机的成本之间的差值。

输入格式

第一行一个整数 n n n 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1n1000),表示商店中可用的计算机的台数。
接下来 n n n 行,每行描述一台计算机,包含三个整数 c i , f i , v i c_i,f_i,v_i ci,fi,vi 1 ≤ c i ≤ 50 1 \leq c_i \leq 50 1ci50 1 ≤ f i ≤ 1 0 9 1 \leq f_i \leq 10^9 1fi109 1 ≤ v i ≤ 1 0 9 1 \leq v_i \leq 10^9 1vi109),分别表示核心数,时钟频率和价格。

接下来一行一个整数 m m m 1 ≤ m ≤ 1000 1 \leq m \leq 1000 1m1000),表示客户的订单总数。
接下来 m m m 行,每行描述一个订单,包含三个整数 C i , F i , V i C_i,F_i,V_i Ci,Fi,Vi 1 ≤ C i ≤ 50 1 \leq C_i \leq 50 1Ci50 1 ≤ F i ≤ 1 0 9 1 \leq F_i \leq 10^9 1Fi109 1 ≤ V i ≤ 1 0 9 1 \leq V_i \leq 10^9 1Vi109),分别表示需要的核心数,最低时钟频率以及预算。

输出格式

仅一行一个整数,表示能够获得的最大总利润。

样例

样例输入
4
4 2200 700
2 1800 10
20 2550 9999
4 2000 750
3
1 1500 300
6 1900 1500
3 2400 4550
样例输出
350

分析

此题很容易发现是01背包(选或不选),不妨把买的和卖的合为同一类型(将一些变量转负)。不过这道题细节很多,本蒟蒻交了十次才AC…请读者在阅读核心代码时仔细想一想边界

代码

#include 
#include 
#include 
#include 
#include 
#define LL long long
using namespace std;
const int MAXN = 4005, MAXX = 100005;
const LL lmi = LONG_LONG_MIN;
struct Node {
	int C, F, V;
}arr[MAXN];
int n, m, sum;
LL dp[MAXX];//剩余j个核心数的最大价值 
bool vis[MAXX];
bool cmp(Node x, Node y) {
	if(x.F != y.F) {
		return x.F > y.F;
	}
	return x.V < y.V;
}
int main() {
	LL ans = 0;
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) {
		scanf("%d%d%d", &arr[i].C, &arr[i].F, &arr[i].V);
		arr[i].V = -arr[i].V;
	}
	scanf("%d", &m);
	for(int i = n + 1; i <= n + m; i ++) {
		scanf("%d%d%d", &arr[i].C, &arr[i].F, &arr[i].V);
		arr[i].C = -arr[i].C;
	}
	sort(arr + 1, arr + 1 + n + m, cmp);
	for(int i = 1; i <= 100005; i ++) {
		dp[i] = lmi;
	}
	vis[0] = 1;
	for(int i = 1; i <= n + m; i ++) {
		if(arr[i].V < 0) {
			sum += arr[i].C;
			for(int j = sum; j >= arr[i].C; j --) {
				if(!vis[j - arr[i].C]) continue;
				vis[j] |= vis[j - arr[i].C];
				dp[j] = max(dp[j], dp[j - arr[i].C] + arr[i].V);
			}
		}
		else {
			for(int j = 0; j <= sum + arr[i].C; j ++) {
				if(!vis[j - arr[i].C]) continue;
				vis[j] |= vis[j - arr[i].C];
				dp[j] = max(dp[j], dp[j - arr[i].C] + arr[i].V);
			}
		}
	}
	for(int i = 0; i <= sum; i ++) {
		if(vis[i]) ans = max(ans, dp[i]);
	}
	printf("%lld", ans);
	return 0;
}

你可能感兴趣的:(DP)