现在的位置: 首页 > 综合 > 正文

UVa #11400 Lighting System Design (例题9-6)

2018年10月14日 ⁄ 综合 ⁄ 共 2226字 ⁄ 字号 评论关闭

书中的状态设计一开始不太能理解。为什么换就要全都换?为什么枚举 j 让前 j 个灯泡选取子问题的最优解,而 j+1 到 i 全部换成 i?不可以隔着换吗?

对于第一个问题,起步时可以进行简单的分类讨论来探寻规律:

1、如果灯泡价格比之前贵,那么我们换灯泡本身是亏钱的。只有当全部灯泡都换完,减掉一个电源的时候,我们才盈利。

2、如果灯泡价格比之前还便宜,那么我们为什么不接着享受这个待遇呢?全部换完还能获得电源加成。

3、如果灯泡价格前后一样,那么全部换完获取电源加成是划算的。

因此灯泡要么不换(第一种情况:最后减掉一个电源也亏),要么全换

因此换灯泡就变成了整体换型号的操作。

对于第二个问题,可以用简单的代数求证:

假设存在连续的XYZ,X换Z划算,X换Y不划算,Y换Z不划算。(即产生了隔着换的情况)。注意如果X换Y划算,Y换Z也划算,那么显然X换Z也划算。如果X换Y划算,X换Z、Y换Z都不划算,这种情况则属于求子问题的最优解。

那么:

X换Z划算 => X.k + X.l * (Z.c - X.c) > 0

X换Y不划算 => X.k + X.l * (Y.c - X.c) < 0

因为数据都是正整数,综合两式可得 Z.c > Y.c

Y换Z是否划算 => Y.k + Y.l * (Z.c - Y.c) ?> 0

因为Z.c > Y.c,所以上式恒大于0,因此Y换Z一定也是划算的。所以最优解永远不会包含“隔着换”的情况。

这样算法的正确性就可以基本确定了。如果不是有书中的提示,估计自己很难独立做出来。

记忆化搜索比递推法慢很多,个人认为主要因为memset和递归函数调用。

递推:Run Time: 0.143

#define UVa  "LT9-6.11400.cpp"		//Lighting System Design
char fileIn[30] = UVa, fileOut[30] = UVa;

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>

using namespace std;

struct Bulb {
    int v, k, c, l;
    Bulb(){v = k = c = l = 0;}
    Bulb(int* a){
        v = a[0]; k = a[1]; c = a[2]; l = a[3];
    }
    bool operator < (const Bulb& b) const {
        return v < b.v;
    }
};

//Global Variables. Reset upon Each Case!
const int maxn = 1000 + 10;
int n;
Bulb bulbs[maxn];
int d[maxn];
int s[maxn];
/////

int main() {
    while(scanf("%d", &n) && n) {
        for(int i = 0; i < n; i ++) scanf("%d%d%d%d", &bulbs[i].v, &bulbs[i].k, &bulbs[i].c, &bulbs[i].l);
        sort(bulbs, bulbs + n);
        int cnt = 0;
        for(int i = 0; i < n; i ++) {
            cnt += bulbs[i].l;
            s[i] = cnt;
        }
        for(int i = 0; i < n; i ++) {
            d[i] = s[i]*bulbs[i].c + bulbs[i].k;
            for(int j = 0; j < i; j ++)
                d[i] = min(d[i], d[j] + (s[i] - s[j])*bulbs[i].c + bulbs[i].k);
        }
        printf("%d\n", d[n-1]);
    }
    return 0;
}

记忆化搜索:0.362s

#define UVa  "LT9-6.11400.cpp"		//Lighting System Design
char fileIn[30] = UVa, fileOut[30] = UVa;

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>

using namespace std;

struct Bulb {
    int v, k, c, l;
    Bulb(){v = k = c = l = 0;}
    Bulb(int* a){
        v = a[0]; k = a[1]; c = a[2]; l = a[3];
    }
    bool operator < (const Bulb& b) const {
        return v < b.v;
    }
};

//Global Variables. Reset upon Each Case!
const int maxn = 1000 + 10;
int n;
Bulb bulbs[maxn];
int d[maxn];
int s[maxn];
/////

int dp(int i) {
    if(d[i]) return d[i];
    d[i] = s[i]*bulbs[i].c + bulbs[i].k;
    for(int j = 0; j < i; j ++)
        d[i] = min(d[i], dp(j) + (s[i] - s[j])*bulbs[i].c + bulbs[i].k);
    return d[i];
}

int main() {
    while(scanf("%d", &n) && n) {
        for(int i = 0; i < n; i ++) scanf("%d%d%d%d", &bulbs[i].v, &bulbs[i].k, &bulbs[i].c, &bulbs[i].l);
        sort(bulbs, bulbs + n);
        memset(d, 0, sizeof(d));
        int cnt = 0;
        for(int i = 0; i < n; i ++) {
            cnt += bulbs[i].l;
            s[i] = cnt;
        }
        printf("%d\n", dp(n-1));
    }
    return 0;
}



抱歉!评论已关闭.