UVA 11400"Lighting System Design"

传送门

 

错误思路

正解

AC代码

 

参考资料:

  [1]:https://www.cnblogs.com/Kiraa/p/5510757.html

 

题意:

  现给你一套照明系统,这套照明系统共包含 n 种类型的灯;

  其中第 i 中类型的灯包含四个参数:vi,ki,ci,li,分别表示

    vi : 第 i 种类型的灯正常工作所需要的电压源;

    ki : 购买电压源 vi 的花费;

    ci : 第 i 种灯泡的单价;

    li : 这套照明系统需要第 i 种灯的个数

  购买第 i 种灯的花费为 costi = ki+ci×li

  总花费为 cost=∑costi

  有如下操作:

  如果 vi ≤ vj , 那么便可将购买的灯 i 换成购买灯 j;

  求对所有灯执行完上述操作后 cost 的最小值;

错误思路:

  贪心策略,如果可以将灯 i 换成灯 j 并且可以使得 cost变小,那么就更换,并且更新 li = 0 , lj += li

  hack样例:

3
1 100 5 10
2 150 14 5
3 300 40 1
0
  正确输出 690
  实际输出 700

错误分析:

  初始,cost1=150 , cost2=220 , cost3=340;

  首先可以判断,灯①可以全部换成灯②,换完后,l1=0,l2=15;

  使得 cost1+cost2 = 150+14×15 = 360 < 150+220;

  但是,此时灯②不能全部换成灯③,cost = cost1+cost2+cost3=360+340=700;

  另一种方案是,灯②全部换成灯③,换完后 cost2+cost3=300+40*6=540 < 220+340;

  灯①既不能换成灯②也不能换成灯③,此时,cost = 690 优于 700;

  也就是说,将①换成灯②可以节省10元,但是如果将灯②换成灯③可以节省20元;

  所以,此题的难点就在于对于可以更换的灯 i , j ,是否将灯 i 换成灯 j 呢?

 


分割线:2019.6.7

  因为要准备考试 6.5 , 6.6 这两天晚上的考试,所以,一直到今天才补了这道题;

  看着紫书上的状态转移方程证明了一下午;

  来看看我今天一下午的成果:

  首先将这 n 种灯按 v 升序排列;

  经过上述操作后,使得总花费最小的方案一定是成片的,什么是成片的呢?

  就是 (1,2,3,...,a-1)(a,...,i,...,b)(b+1,..,j,..,d)(...,n) 这么划分是使得总花费最小的划分方案;

  (a,....,b) : 第 [a,...,b-1] 种灯都换成第 b 种灯;

  为什么这就是答案呢?

  为什么不能是穿插着是答案呢?

  用反证法证明,对于 (a,...,i,...,b)(b+1,..,j,..,d) 这两个划分,假设将 i,j 互换后的划分为使得总花费最小的划分;

  首先定义:

    sum1 = la+la+1+...+li+...+lb;//[a,b]区间的总灯泡个数

    sum2 = lb+1+lb+2+...+lj+...+ld;//[b+1,d]区间的总灯泡个数

    //交换i,j灯泡后的总个数

    sum3 = sum1-li+lj;

    sum4 = sum2-lj+li;

    sum = sum1+sum2 = sum3+sum4;

  ① cost{ (a,...,j,...,b)(b+1,..,i,..,d) } < cost{ (a,...,i,...,b)(b+1,..,j,..,d) };

  ② cost{ (a,...,j,...,b)(b+1,..,i,..,d) } < cost{ (a,............................,d) };

  由①可得:

    (kb+sum3×cb)+(kd+sum4×cd) < (kb+sum1×cb)+(kd+sum2×cd)

  化简得:

    (sum3-sum1)cb < (sum2-sum4)cd

  由②可得:

    (kb+sum3×cb)+(kd+sum4×cd) < kd+sum×cd

  化简得:

    cb < cd;

正解:  

  首先可以得出这样一个结论:每种类型的灯泡,要么全换成其他类型的,要么全都不换;

  定义dp[ i ]表示前 i 个灯泡得最小花费,sum[ i ]表示前 i 个灯泡得总个数;

  对于两类灯泡 i 和 j,i 可以换成 j 的条件是:

  1) v> vi

  2) j 一定存在于最优解中(保证 k不被省去)

  3) ki+li×ci < lcj

  基于条件(1),首先将灯泡按照电压从小大到大排序;

  假设前 i-1 个灯泡经过最优的替换后,新的灯泡序列为 b1,…,bj,bj+1,…bk(bi表示没被合并的灯泡编号,并且按照电压非降序排列);
  b和 bj+1 的关系一定满足:
    ①kb[ j ]+lb[ j ]×cb[ [j ] < lb[ j ]*cb[ j+1](否则 b可被 bj+1 替换,与当前为最优解的假设矛盾);

  现在我们考虑用第 i 个灯泡 a替换的情况;

  假设 b可以被 a替换,那么有

    ②kb[ j ]+lb[ j ]×cb[ j ] > lb[ j ]×ca[ i ]

  由式 ①② 可得  ca[ i ] < cb[ j+1],即 bj+1 可被 a替换; 

  同理,bj+2~b的所有灯泡都可以被 ai 替换;

  换句话说,对于前 i-1 个灯泡 a1~aj~ai-1,如果存在 j(1<j<i-1),aj+1可以被 ai 替换,

  那么 aj+1~ai-1 的所有灯泡都可以被 ai 替换,而a1~a灯泡的最小费用已经算出为dp[ j ]。

  这样我们就得出了 a的替换方法:前 j 个灯泡用之前计算出的最优方案 d[ j ] 购买,

  剩下 j+1~i 个灯泡全用 a替换,枚举 j 从 0 到 i-1,根据前面的讨论得知不会漏解;

  则状态转移方程 d[ j ]=min{ d[ j ]+c[ i ]×(s[ i ]-s[ j ])+k[ i ] };

  最终答案就是 dp[n];

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b);
 5 const int maxn=1e3+50;
 6 
 7 int n;
 8 struct Data
 9 {
10     int v,k,c,l;
11     bool operator < (const Data &obj) const
12     {
13         return v < obj.v;
14     }
15 }_data[maxn];
16 int dp[maxn];
17 int sum[maxn];
18 
19 int Solve()
20 {
21     sort(_data+1,_data+n+1);
22     sum[0]=0;
23     for(int i=1;i <= n;++i)
24         sum[i]=sum[i-1]+_data[i].l;
25     memF(dp,INF,n);
26     dp[0]=0;
27     for(int i=1;i <= n;++i)
28         for(int j=0;j < i;++j)
29             dp[i]=min(dp[i],dp[j]+(sum[i]-sum[j])*_data[i].c+_data[i].k);
30 
31     return dp[n];
32 }
33 int main()
34 {
35     while(~scanf("%d",&n) && n)
36     {
37         for(int i=1;i <= n;++i)
38             scanf("%d%d%d%d",&_data[i].v,&_data[i].k,&_data[i].c,&_data[i].l);
39         printf("%d\n",Solve());
40     }
41     return 0;
42 }
View Code

 

posted @ 2019-06-05 11:00  HHHyacinth  阅读(195)  评论(0编辑  收藏  举报