Uva11400照明系统设计

题意给定n种类型灯泡,每个灯泡给出其电压v,电源花费k,每个灯的花费c和需求量l,现在通过用电压大的灯泡替换某些电压小的灯泡来减小总花费,求最小的花费。
思路:(原文:https://blog.csdn.net/yanzheshi/article/details/47069189

首先要说明的是,为求得最小花费,对于某种灯泡,要么全部替换,要么全不替换,这个很容易证明。

这个问题难就难在如何找子问题。如果先按灯泡电压把灯泡从小到大进行排序,定义dp[i]为替换第i种灯泡后前i种灯泡的最小花费,因为对一种替换情况,不知道用来替换的灯泡后来会不会再用,如果不用相当于不替换的情况下多用了一个电源,这样不一定会达到最优,所以这样定义不行。这样当前的决策会影响到后面的决策。对于这种情况,我们应该对决策进行一定的限制: 求前i个灯泡的最小花费时,只允许用第i种灯泡进行替换! 如何替换呢? 只能替换1 到i 中序号连续的灯泡!!! 即决策应为选择一个j,替换掉序号为 j 到i - 1的所有灯泡,使得前i号灯泡花费最小。那么最终 dp[n]即为答案。即d[i]为只考虑前i种灯泡的最小花费,状态转移方程:d[i] = min{d[i] + (s[i] - s[j]) * c[i] + k[i]} 其中s[i]为前i种灯泡的总数量。

但这样做是否正确呢,首先上面的方法在求前i 个灯泡的最小花费时,只能用第i个灯泡替换,这样并不影响,因为通过循环所有的灯泡都会用来替换。 问题关键是只考虑替换连续区间的灯泡造成解丢失的情况。比如说会不会出现最优解是序号为1, 3的灯泡被一种灯泡替换,序号为2的被另一种替换或不被替换。 假设这种情况下是最小花费,那么替换序号2的灯泡的单价一定小于替换序号1的灯泡的单价,否则不会是最小值,既然替换序号2的灯泡的单价小于替换序号1的灯泡的单价,那么用替换2的灯泡去替换灯泡1,就会产生更小的花费,这与假设向矛盾,所以假设不成立,即前面的决策不会漏掉答案。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 1<<30;
const int N = 1005;

struct Light{
	int v,k,c,l;
	bool operator<(const Light& rhs)const{
		return v < rhs.v;
	}
};
Light lights[N];
int s[N], d[N];

int main()
{
	int n;
	
	//freopen("in.txt","r",stdin);
	while(scanf("%d",&n) == 1&&n){
		
		for(int i = 1; i <= n; ++i)
			scanf("%d %d %d %d",&lights[i].v,&lights[i].k,&lights[i].c,&lights[i].l);
			
		sort(lights+1,lights+n+1);
		
		s[0] = 0;
		for(int i = 1; i <= n; ++i){
			s[i]= s[i-1] + lights[i].l;
		}
	
		for(int i = 1; i <= n; ++i) d[i] = INF;
		d[0] = 0;
		for(int i = 1; i <= n; ++i){
			for(int j = 0; j < i; ++j){
				d[i] = min(d[i], d[j] + (s[i]-s[j])*lights[i].c + lights[i].k);
			}
		}
		
		printf("%d\n",d[n]);
	}
	
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值