UVA14000 Lighting System Design

一. 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;
}



你可能感兴趣的:(UVA14000 Lighting System Design)