上升点列

题目描述

在一个二维平面内,给定 n 个整数点 (xi​,yi​),此外你还可以自由添加 k 个整数点。

你在自由添加 k 个点后,还需要从 n+k 个点中选出若干个整数点并组成一个序列,使得序列中任意相邻两点间的欧几里得距离恰好为 1 而且横坐标、纵坐标值均单调不减,即 xi+1​−xi​=1,yi+1​=yi​ 或 yi+1​−yi​=1,xi+1​=xi​。请给出满足条件的序列的最大长度。

输入格式

第一行两个正整数 n,k 分别表示给定的整点个数、可自由添加的整点个数。

接下来 n 行,第 i 行两个正整数 xi​,yi​ 表示给定的第 i 个点的横纵坐标。

输出格式

输出一个整数表示满足要求的序列的最大长度。

输入输出样例

输入 #1

复制代码
8 2
3 1
3 2
3 3
3 6
1 2
2 2
5 5
5 3

输出 #1

复制代码
8

输入 #2

复制代码
4 100
10 10
15 25
20 20
30 30

输出 #2

复制代码
103

说明/提示

【数据范围】

保证对于所有数据满足:1≤n≤500,0≤k≤100。对于所有给定的整点,其横纵坐标 1≤xi​,yi​≤10^9,且保证所有给定的点互不重合。对于自由添加的整点,其横纵坐标不受限制。

测试点编号 n≤ k≤ xi​,yi​≤
1∼2 10 0 10
3∼4 10 100 100
5∼7 500 0 100
8∼10 500 0 10^9
11∼15 500 100 100
16∼20 500 100 10^9
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

struct node
{
	int x,y;//1e9 1e9
};
bool operator<(node n1,node n2)
{
	return n1.x<n2.x||(n1.x==n2.x&&n1.y<n2.y);
}
node p[510];//5e2
int dp[510][110];//5e2
int main()
{
	int n,k;//5e2 1e2
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		int x,y;//1e9 1e9
		cin>>x>>y;
		p[i]={x,y};
	}
	sort(p+1,p+n+1);
	int maxn=0;//5e2
	for(int i=1;i<=n;i++)
	{
		int x=p[i].x,y=p[i].y;
		for(int l=0;l<=k;l++)
		{
			for(int j=1;j<i;j++)
			{
				int dx=x-p[j].x,dy=y-p[j].y;
				if(dx>=0&&dy>=0&&dx+dy<=l+1)
					dp[i][l]=max(dp[i][l],dp[j][l-dx-dy+1]+dx+dy);
			}
			if(dp[i][l]==0)
				dp[i][l]=l+1;
			maxn=max(maxn,dp[i][l]);
		}
		
	}
	cout<<maxn;
	
	return 0;
}

---------------------------------------前方级别:洛谷黄题,2022CSP-J T3---------------------------------------

主体思想及算法:

DP中的LIS(最长上升子序列)变形。

LIS模板:

cpp 复制代码
for(int i=1;i<=n;i++)
{
	dp[i]=1;
	for(int j=1;j<i;j++)
		if(a[i]>a[j])
			dp[i]=max(dp[i],dp[j]+1);
	maxn=max(maxn,dp[i]);
}
cout<<maxn;

变形后dp[i][j]代表第i个点加j个点的最大答案。

代码解读:

main():输入n、k、xi、yi。xi和yi记录在一个node(见node)类型的p数组里,p[i]代表编号为i的一组xy。但是由于下方某些原因,p数组不得使用原顺序,需要按排序(具体规则见operator<())后的顺序。排序后定义一个maxn,由于此题为LIS变形,这个maxn自然代表答案啦!不过初始置为k+1,因为但凡有一个点,他添加k个点也有k+1了。

第一层循环:首先不管加点的事儿,先定义xy分别为p[i]的xy,一会儿将多次使用。

第二层循环:请注意,这层循环的变量l代表可以加l个点,是从0到k!!!因为你可以选择独自优秀不须加点。

第三层循环:这个j也要注意,是到i-1,由于之前的排序,我们保证到i之后肯定都不行了,所以也都没用了。再设两个临时变量dx和dy,代表x-p[j].x和y-p[j].y(同样,一会儿将多次使用)。如果dx和dy均大于等于0,也就是说按照要求可以连线,且dx加dy小于等于l加1,这里注意加1,因为假设l是0,dx加dy就得是1。如果满足上句话这些条件,那么dp[i][j]就max=dp[j][l-dx-dy+1]+dx+dy。

回到第二层循环,因为每一个dp[i][l]都是独立的,所以maxn等要在此处单独结算。注意如果dp[i][l]是0,要给他设为l+1,毕竟添加l个点就有l+1了。最后maxn max=dp[i][l]。

回到主函数,输出maxn。

node:一个x一个y。

operator<():重载小于运算符,如果x不同x小者小;否则y小者小。

相关推荐
Swift社区1 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman1 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
IT 青年2 小时前
数据结构 (1)基本概念和术语
数据结构·算法
Dong雨2 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展
SoraLuna2 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
liujjjiyun3 小时前
小R的随机播放顺序
数据结构·c++·算法
¥ 多多¥3 小时前
c++中mystring运算符重载
开发语言·c++·算法
trueEve4 小时前
SQL,力扣题目1369,获取最近第二次的活动
算法·leetcode·职场和发展
天若有情6734 小时前
c++框架设计展示---提高开发效率!
java·c++·算法
ahadee4 小时前
蓝桥杯每日真题 - 第19天
c语言·vscode·算法·蓝桥杯