zoukankan      html  css  js  c++  java
  • 【神仙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]中的灯泡个数(非种类数)。

          正确性证明:

            方程的直观解释是先选取前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
    ",frog[n]);
            n=0;qr(n);
        }
        return 0;
    }

    Summary

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

  • 相关阅读:
    C#’s ~ vs Java’s finalize
    做Java开发这一年
    assertThat, assertEquals, assertTrue
    给Cuke4Duke添加一个AfterAll标签(一):使用Cuke4Duke
    心理问题的根源
    何谓数学
    人生谁看透
    人本主义与自由意志
    哲学的基本问题
    贫穷与教育
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9236117.html
Copyright © 2011-2022 走看看