洛谷 题解 P2439 【[SDOI2005]阶梯教室设备利用】

大佬们的\(DP\)有点复杂,让我来讲些易懂的。

想必大家都会写“最长不下降子序列问题”(\(LIS\)),我们也可以将这道题转化为\(LIS\)呀!

怎么转化呢?

我们知道,\(LIS\)中不下降指的是数字大小,而在这道题中,我们可以用不下降来指代演讲的时间,及后面的演讲开始时间不低于前面演讲的结束时间。

\(LIS\)中,\(f_i\)指代的是最长不下降子序列的长度,这里可以指代最长的演讲时间;而\(LIS\)\(f_i\)更新是因为在比它更小的数中,有比\(f_i\)更长的序列,这里可以认为,当前面的某个演讲加上之前的演讲,比\(f_i\)更大时,可以更新。

简而言之,原\(LIS\)的方程为:

\(f_i=\max(f_i,f_j+1)\ (1<=j<i,a_j<=a_i)\)

类比,这里的方程可以写为

\(f_i=\max(f_i,f_j+a_i.len)\ (1<=j<i,a_j.ed<=a_i.st)\)

(其中\(len\)表示演讲时间长度,\(st\)表示演讲开始时间,\(ed\)表示演讲结束时间)

转化成功了!

最后讲一下细节:

我们为了保持时间最长,一定要排序,按开始时间大小排序。

没了。

\(AC\) \(Code\)

#include <iostream>
#include <algorithm>
using namespace std;

struct speak{
    int st, ed, len;
};//结构体更方便推算和排序
speak a[10010];
bool cmp(speak x, speak y) {
    return x.st < y.st;
}//自定义cmp函数,用来排序。如果想要更快可重载运算符

int n, f[10010], ans;

int main() {
    cin >> n;
    for (int i=1; i<=n; i++) {
        cin >> a[i].st >> a[i].ed;
        a[i].len = a[i].ed-a[i].st;//时间计算式
    }
    sort(a+1, a+1+n, cmp);
    for (int i=1; i<=n; i++) {
        f[i] = a[i].len;//初始化:假设在它前面没有演讲,最短时间也是这个演讲的时间
        for (int j=1; j<i; j++) {
            if (a[j].ed <= a[i].st && f[i] < f[j]+a[i].len)
                f[i] = f[j]+a[i].len;
        }
        ans = max(ans, f[i]);//更新答案
    }
    cout << ans << endl;
    return 0;//完结撒花!
}

猜你喜欢

转载自www.cnblogs.com/zyh-cr7/p/12237218.html