大佬们的\(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;//完结撒花!
}
洛谷 题解 P2439 【[SDOI2005]阶梯教室设备利用】
原文:https://www.cnblogs.com/zyh-cr7/p/12237218.html