UVa 11400 - Lighting System Design (dp)

题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2395

要换灯泡的话,一定是这个种类的全换,将灯泡按电压排序,如果有灯的种类要替换成灯 \(i\),那么灯 \(i\)\(c[i]*l[i]+k[i]\) 一定是这段区间中最小的,最终替换成的所有灯泡的 \(c[i]*l[i]+k[i]\) 一定是递增的,如下图

红线是灯泡原来的值,黑框是替换以后的值的样子

所以我们就可以考虑 \(dp\),令 \(dp[i]\) 表示前 \(i\) 个灯泡的答案,转移是考虑从哪一段开始将这些灯泡都替换成灯泡 \(i\)

\[dp[i] = max{dp[j]+(s[j]-s[i])*c[i]+k[i]}(0<=j<i) \]

其中 \(s[i]\) 表示前 \(i\) 个灯泡的总数量

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1010;

int n;
int s[maxn], dp[maxn];

struct Lamp{
	int v, k, c, l;
	
	bool operator < (const Lamp &x) const{
		return v < x.v;
	}
}a[maxn];

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	while(scanf("%d", &n) == 1 && n){
		for(int i = 1 ; i <= n ; ++i){
			scanf("%d%d%d%d", &a[i].v, &a[i].k, &a[i].c, &a[i].l);
		}
		sort(a + 1, a + 1 + n);
		
		s[0] = 0;
		for(int i = 1 ; i <= n ; ++i) s[i] = s[i-1] + a[i].l; 
		
		memset(dp, 0x3f, sizeof(dp));
		dp[0] = 0;
		
		for(int i = 1 ; i <= n ; ++i){
			for(int j = 0 ; j < i ; ++j){
				dp[i] = min(dp[i], dp[j] + (s[i] - s[j]) * a[i].c + a[i].k);
			}
		}
		printf("%d\n", dp[n]);
	} 
	return 0;
}
posted @ 2021-07-22 10:55  Tartarus_li  阅读(22)  评论(0编辑  收藏  举报