#include const int N = 510; //性能:第12号测试点,时间最长,65ms /* 搜索代码:暴力枚举每次选择哪个点,能选就选,维护剩下几个自由点,加个记忆化即可通过 */ using namespace std; int n, m, ans; int x[N], y[N]; //对于二维坐标,两个x,y数组 int f[N][N]; //结果数组 //从u点出发,还有r个虚拟点可用,可以获得的最长序列长度是多少 int dfs(int u, int r) { if (~f[u][r]) return f[u][r]; //计算过则直接返回 int ans = r + 1; //剩余r个虚拟点,再加上当前点u,最起码能有r+1点的序列长度 for (int i = 1; i <= n; i++) { //谁能做为我的后续点 if (u == i) continue; //自己不能做为自己的直接后续点 if (x[i] < x[u] || y[i] < y[u]) continue; //排除掉肯定不可能成为我后续点的点 int d = x[i] - x[u] + y[i] - y[u] - 1; // u->i之间缺少 多少个虚拟点 if (d > r) continue; //如果需要的虚拟点个数大于剩余的虚拟点个数,那么i 无法做为u的后续点 ans = max(ans, dfs(i, r - d) + d + 1); //在消耗了d个虚拟点之后,成功到达了i这个点; //①已经取得的序列长度贡献u和d个虚拟点,共d+1个 //②问题转化为求未知部分:以i点为出发点,剩余虚拟点个数r-d个的情况下可以获取到的最长序列长度 } return f[u][r] = ans; //记忆化 } int main() { //文件输入 // freopen("point.in", "r", stdin); memset(f, -1, sizeof f); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> x[i] >> y[i]; for (int i = 1; i <= n; i++) ans = max(ans, dfs(i, m)); printf("%d\n", ans); return 0; }