一种dp的解法
首先对于每一个节目都是看与不看的问题,可以选择对开始时间排序后,按顺序考虑每一个节目,排序后优秀的地方在于,你考虑一个节目的时候,最优解的选取方法里,在你当前节目之前会选取到的节目都是在这个顺序之前会出现,这样就让一个无序的节目强行有序了起来。
先对时间去离散化,由于数据范围是在太小,所以很暴力的可以设计dp的转移方程F[i][j][z]代表当前判断到第i个节目,第一台机子的下一次可录制时间为j,第二台机子的下一次可录制时间为z。
方程有了后我们考虑转移,当前的节目可以选或者不选,如果不选那必然是继承之前的答案,如果选那么就考虑放在第一台机子或者第二台机子。我们思考如果用第一/二台机子去录那么对应机子结束时间是固定的。假设我们第一台机子去录这个节目那么就是f[i][node[i].E][z],node[i].E是结束时间,我们需要枚举的是第三维度,上一个状态可以转移到当前状态就仅又f[i-1][1-node[i].S][z],node[i].S是开始时间,则你必须第一台机子可以录制下一个的时间在你节目开始之前。那么转移其实就做好了,这一步你可以额外开数组记录一个上一个状态的前缀max就可以了。
int yuan[max_ << 1], ynn, N, f[max_][max_][max_];
struct kk {
int S, E;
}node[max_];
bool cmp(const kk&t1, const kk&t2) {
if (t1.S == t2.S)return t1.E < t2.E;
return t1.S < t2.S;
}
int maxv[max_][max_],maxv2[max_][max_];
int ans = 0;
il void update(int id) {
for (int i = 0; i <= ynn; i++) {
maxv[i][0] = f[id][i][0]; ans = max(ans, maxv[i][0]);
maxv2[0][i] = f[id][0][i]; ans = max(ans, maxv2[0][i]);
for (int j = 1; j <= ynn; j++) {
maxv[i][j] = max(maxv[i][j - 1], f[id][i][j]); ans = max(ans, maxv[i][j]);
maxv2[j][i] = max(maxv2[j - 1][i], f[id][j][i]); ans = max(ans, maxv2[j][i]);
}
}
}
signed main() {
N = read();
for (int i = 1; i <= N; i++) {
node[i].S = read(); node[i].E = read();
yuan[++ynn] = node[i].S; yuan[++ynn] = node[i].E;
}
sort(yuan + 1, yuan + 1 + ynn);
ynn = unique(yuan + 1, yuan + 1 + ynn) - yuan - 1;
for (int i = 1; i <= N; i++) {
node[i].S = lower_bound(yuan + 1, yuan + 1 + ynn, node[i].S) - yuan;
node[i].E = lower_bound(yuan + 1, yuan + 1 + ynn, node[i].E) - yuan;
}
sort(node + 1, node + 1 + N, cmp);
memset(f, 128, sizeof(f));
f[0][0][0] = 0;
update(0);
for (int i = 1; i <= N; i++) {
//不看这个电视
for (int j = 0; j <= ynn; j++) {
for (int z = 0; z <= ynn; z++) {
f[i][j][z] = f[i - 1][j][z];
}
}
//看这个电视
for (int j = 0; j <= ynn; j++) {
f[i][node[i].E][j] = max(f[i][node[i].E][j], maxv2[node[i].S][j] + 1);
f[i][j][node[i].E] = max(f[i][j][node[i].E], maxv[j][node[i].S] + 1);
}
update(i);
}
cout << ans;
return 0;
}