【神仙DP】【UVa11400】Lighting System Design

传送门

Description

Translation

题目大意:有一个照明系统需要用到n种灯,每种灯的电压为V,电源费用K,每个灯泡费用为C,需要该灯的数量为L。注意到,电压相同的灯泡只需要共享一个对应的电源即可,还有电压低的灯泡可以被电压高的灯泡替代。为了节约成本,你将设计一种系统,使之最便宜。

Input

Sample Input

3
100 500 10 20
120 600 8 16
220 400 7 18
0

Sample Output

778

Hint

  所有相同电压的灯泡共享一个电源。n<=1000。

Solution

  注意到一种灯泡要么不换要么全换。

    证明:如果灯泡只换一部分,那么说明被替换的一部分比不换省钱,那么全部换要比换那些省钱。如果不换,那么肯定都不换。

   接下来考虑阶段,由于只能小灯泡换成大灯泡,也就是说小灯泡怎么选对大灯泡没有影响,所以考虑以电压v升序作为阶段。设前i种灯泡的最优解是f[i]。

则有状态转移方程:

      f[i]=min{f[j]+(sum[i]-sum[j])*c+k}。其中sum为前缀和,表示区间[0,i]中的灯泡个数(非种类数)。

扫描二维码关注公众号,回复: 1774208 查看本文章

      正确性证明:

        方程的直观解释是先选取前j个的最优解,然后剩下的全部买i型电源。

        考虑到可能被hack的数据是[j+1,i]中有几种不选电源i,选择更大的电源。那么原灯泡会适配大电源,大电源在转移时一定被选择,那么电源花费不变,如果购买大电源灯泡花费更少,那么第i个也会被转移,满足无后效性。故方程成立。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1010

inline void qr(int &x) {
    char ch=getchar();int f=1;
    while(ch>'9'||ch<'0')    {
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')    x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x*=f;
    return;
}

inline int max(const int &a,const int &b) {if(a>b) return a;else return b;}
inline int min(const int &a,const int &b) {if(a<b) return a;else return b;}
inline int abs(const int &x) {if(x>0) return x;else return -x;}

inline void swap(int &a,int &b) {
    int c=a;a=b;b=c;return;
}

int n,frog[maxn],sum[maxn];

struct Light {
    int v,k,c,l;
};
Light MU[maxn];

void clear() {
    std::memset(MU,0,sizeof MU);
    std::memset(frog,0x3f,sizeof frog);
    std::memset(sum,0,sizeof sum);
    frog[0]=0;
}

inline bool cmp(const Light &a,const Light &b) {return a.v<b.v;}

int main() {
    qr(n);
    while(n) {
        clear();
        for(int i=1;i<=n;++i) {
            qr(MU[i].v);qr(MU[i].k);qr(MU[i].c);qr(MU[i].l);
        }
        std::sort(MU+1,MU+1+n,cmp);
        for(int i=1;i<=n;++i)    sum[i]=sum[i-1]+MU[i].l;
        for(int i=1;i<=n;++i) {
            for(int j=0;j<i;++j) {
                frog[i]=min(frog[i],frog[j]+(sum[i]-sum[j])*MU[i].c+MU[i].k);
            }
        }
        printf("%d\n",frog[n]);
        n=0;qr(n);
    }
    return 0;
}

Summary

需要排序的题,一定排序完再写前缀和!!!

猜你喜欢

转载自www.cnblogs.com/yifusuyi/p/9236117.html