UVA14000 Lighting System Design

来源:互联网 发布:四大名助 综艺 知乎 编辑:程序博客网 时间:2024/06/05 05:34

一. Vjudge链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26154

二. 题目大意:给出灯泡的4个属性,电压,所需电源的花费,每个灯泡所需的花费,所需要灯泡的数量,并且不同的灯泡需要不同的电源,电压低的灯泡可以被电压高的灯泡换掉。求最小的花费。

三. 思路:存在最小花费的原因:一是把一种灯泡全部换掉了,然后节省了一个电源的花费。二是由于灯泡的单个花费比较大,用一个单个花费少的灯泡把它换掉。而第二种情况,如果能换1个,那么全部换了就会更省钱,因此存在最小花费只有一种情况,一种灯泡被另一种全部换掉,若干次换,或者不换,取得了最优解。考虑只有2个的情况,那么有2种可能,各自用自己的电源,或者电压大的灯泡替代电压小的灯泡,之中取最小的。而再加入一个电压更大的灯泡,看起来有2^(3-1),共4种情况,而实际上如果电压第二大的替代了电压最小的,那么就只要考虑电压最大的会不会替代前面的2个灯泡就行了。如果电压第二大的没有替代电压最小的,那么还是只要考虑电压最大的会不会替代前面的最优解,或者它不替代就形成了当前的最优解。先将灯泡按电压大小排序,让前面的灯泡变得可以被后面的灯泡替代。

于是动态转移方程就出来了:dp[i] = min(dp[j] + (sum[i]-sum[j])*num[i] + supply) dp[i]记录前i个的最优解,sum[i]记录前i个灯泡总数,num[i]记录第i个灯泡的数量,supply表示电源花费。j严格小于i。表示要得到当前的最优解,只要寻找前面的所有最优解加上被替代的灯泡的花费。也就是j之后的灯泡都是被i代替了。

而实际上,这个模型和最长上升子序列有相似之处,最长上升子序列求法也是扫一遍前面所有的最优解,取(有符合条件的最优解+1,或者不符合条件最优解就保留长度)的最大值,赋值给当前值。

四. 代码:

#include <iostream>#include <cstdio>#include <queue>#include <cstring>#include <cmath>#include <algorithm>#include <stack>using namespace std;const int MAX_N = 1025,          INF = 0x3f3f3f3f;struct Light{    int vol, supply, cost, num;}light[MAX_N];int dp[MAX_N], lightSum, sum[MAX_N];bool cmp(Light a, Light b){    return a.vol < b.vol;}int main(){    //freopen("in.txt", "r", stdin);    int i, j;    while(~scanf("%d", &lightSum) && lightSum){        for(i = 1; i <= lightSum; i++)            scanf("%d%d%d%d", &light[i].vol, &light[i].supply,                              &light[i].cost, &light[i].num);        sort(light + 1, light + lightSum + 1, cmp);        dp[0] = 0;        sum[0] = 0;        for(i = 1; i <= lightSum; i++)            sum[i] = light[i].num, sum[i] += sum[i-1];        for(i = 1; i <= lightSum; i++){            int tmp = INF;            for(j = 0; j < i; j++)                tmp = min(tmp, dp[j] + (sum[i]-sum[j])*light[i].cost + light[i].supply);            dp[i] = tmp;        }        printf("%d\n", dp[lightSum]);    }    return 0;}


0 0