【[CSP-J 2022] 上升点列】
题目
[CSP-J 2022] 上升点列
 题目描述
 在一个二维平面内,给定 n 个整数点 (x i ,y i ),此外你还可以自由添加 k 个整数点。
 你在自由添加 k 个点后,还需要从 n+k 个点中选出若干个整数点并组成一个序列,使得序列中任意相邻两点间的欧几里得距离恰好为 1 而且横坐标、纵坐标值均单调不减,即 x i+1 −x i =1,y i+1 =y i 或 y i+1 −y i =1,x i+1 =x i 。请给出满足条件的序列的最大长度。
输入格式
 第一行两个正整数 n,k 分别表示给定的整点个数、可自由添加的整点个数。接下来 n 行,第 i 行两个正整数 x i ,y i 表示给定的第 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.各点按x、y排序
 2.状态:到达各点的最多序列
 3.状态转移:到达该点的最多序列=前面所有点中的最多序列
 4.转移方程:f[i][n]=max(f[i][n],f[j][k-dis(i,j)]+dis(i,j)+1)
 f[当前点][借的点数]=max(f[当前点][借的点数],
 f[当前点前的每个点][当前借的点数-i到j两点间需要的点数]
 +
 i到j两点间需要的点数
 +
 i点本身
 )
 5.三层循环
 一层,遍历每个点(i)
 二层,遍历i前所有点(j)
 三层,遍历能借的点数0到k-dis(i,j)
图解
![【[CSP-J 2022] 上升点列】](https://i-blog.csdnimg.cn/direct/db1a365583bb4831970e34796032285a.png)
两点间欧几里得距离
![【[CSP-J 2022] 上升点列】](https://i-blog.csdnimg.cn/direct/b27b08cd9c1b4fd8a7239c0d5e708dd6.png)
代码
#include using namespace std;int n,//整数点数 k,//可添加整数点数 x,y,//整数点的坐标 ans,//最多序列 f[501][101];//在借得不同数点情况下到达每个点的最多序列数 //f[i][x]=max(f[i][x],f[j][x-dis(i,j)]+dis(i,j)+1) struct point{int x,y;bool operator<(const point p2)const{if(x==p2.x)return y<p2.y;return x<p2.x;}}p[501];int dis(int i2,int i1){return p[i1].x-p[i2].x+p[i1].y-p[i2].y-1;}void view(){cout<<\"各点\"<<endl;for(int i=0;i<n;i++)cout<<p[i].x<<\",\"<<p[i].y<<endl;}void view2(){cout<<\"最多序列\"<<endl;cout<<\"添加\\t\";for(int x=0;x<=k;x++)cout<<x<<\'\\t\';cout<<endl;for(int i=0;i<n;i++){cout<<p[i].x<<\",\"<<p[i].y<<\"\\t\";for(int x=0;x<=k;x++)cout<<f[i][x]<<\'\\t\';cout<<endl;}}int main(){freopen(\"point.in\",\"r\",stdin);cin>>n>>k;for(int i=0;i<n;i++){cin>>x>>y;p[i]=point{x,y}; }//view();sort(p,p+n);view();for(int i=0;i<n;i++){//遍历所有点 f[i][0]=1;//初始化,每个点序列起码有1 for(int j=0;j<i;j++)//遍历前面的所有点 if(p[j].y<=p[i].y){//如果是升序(右上) int m=dis(j,i);//欧几里得距离 for(int x=0;x+m<=k;x++)//j已经加的点+现在i到j加的点不超过k f[i][x+m]=max(f[i][x+m],f[j][x]+dis(j,i)+1);/*第i点用了x+m个点后的最多序列=以下中最大本来的最多序列i前j点用了x个点后的最多序列,加上i到j需要的点,+i点本身 */}}view2();for(int i=0;i<n;i++)//遍历所有点,不一定是最后一个序列最多 for(int j=0;j<=k;j++)//用添加点最少而序列最多的 ans=max(ans,f[i][j]+k-j);//在必须用的点基础上还可以用k剩余的点 cout<<ans;return 0;}
数据
![【[CSP-J 2022] 上升点列】](https://i-blog.csdnimg.cn/direct/d441183598384348a6f4bffcfe93d14b.png)


