71 lines
2.3 KiB
C++
71 lines
2.3 KiB
C++
#include <bits/stdc++.h>
|
||
using namespace std;
|
||
const int N = 510;
|
||
const int M = 110;
|
||
struct Node {
|
||
int x, y;
|
||
/*
|
||
Q1:为什么要排序?
|
||
A:因为要DP,需要解决无后效性。也就是有一定的单调性,从左向右,从上向下填表,填完的数值不能再被修改,需要有一定的依赖关系顺序
|
||
|
||
Q2:按什么来排序?
|
||
A:可以按x+y来排序,也可以按先x,后y的方式来排序,都是一样的。
|
||
|
||
1.按x+y排序
|
||
const bool operator<(const Node &t) {
|
||
return x + y < t.x + t.y;
|
||
}
|
||
*/
|
||
// 2.先按x,再按y排序
|
||
const bool operator<(const Node &t) {
|
||
if (x == t.x) return y < t.y;
|
||
return x < t.x;
|
||
}
|
||
} a[N];
|
||
|
||
int f[N][M];
|
||
int ans;
|
||
|
||
int main() {
|
||
// 文件输入
|
||
// freopen("point.in", "r", stdin);
|
||
|
||
int n, m;
|
||
cin >> n >> m;
|
||
|
||
for (int i = 1; i <= n; ++i) cin >> a[i].x >> a[i].y;
|
||
sort(a + 1, a + 1 + n);
|
||
|
||
// dp初始化,最后一个点是以i号点选中,并且,使用了j个虚拟点情况下,获得的最长序列长度
|
||
for (int i = 1; i <= n; i++)
|
||
for (int j = 0; j <= m; j++)
|
||
f[i][j] = j + 1; // 以i点结束,并且,使用了j个虚拟点,最起码可以构成一个最长长度为j+1的序列
|
||
|
||
// 状态转移
|
||
for (int i = 1; i <= n; i++) // 枚举每个原始点
|
||
for (int j = 1; j < i; j++) { // 枚举每个前序点
|
||
if (a[i].x < a[j].x || a[i].y < a[j].y) continue; // 如果j不在i的左下方,无效转移
|
||
int d = a[i].x - a[j].x + a[i].y - a[j].y - 1; // j->i 需要增加的虚拟点个数
|
||
|
||
/*
|
||
讨论j点的哪些子状态 可以转移到 i的哪些子状态?
|
||
思考一下f[j]的二维状态,最小值是0,最大值是m
|
||
现在f[j]的二维状态变化量是固定的,是d
|
||
所以需要枚举j的所有以转移的二维状态值:0 ~ m-d
|
||
*/
|
||
for (int k = 0; k <= m - d; k++) {
|
||
// f[j][k]是前序状态,可以通过+d转移到新的状态
|
||
// f[j][k+d]+d+1 -> f[i][k+d]
|
||
f[i][k + d] = max(f[i][k + d], f[j][k] + d + 1);
|
||
|
||
// 在状态转移完成后,收集一下答案
|
||
// 小坑一个:给你m个虚拟点,你最后没用了的话,就是浪费,因为最起码,
|
||
// 把多出来的放在最后就可以增长序列长度
|
||
ans = max(ans, f[i][k + d] + m - k - d); // 更新序列最长长度
|
||
}
|
||
}
|
||
|
||
// 输出结果
|
||
printf("%d\n", ans);
|
||
return 0;
|
||
} |