Title

CSP-J2022 T4 上升点列

蒟蒻的第一篇题解,望过

题目传送门

题目大意

平面上有n个点,还可以添加k个点,选取一个点序列使得序列中的每一个点的坐标非严格递增。

本蒟蒻的思路历程:点排序后dp但是我太蒻了不会dp——>在看到n的取值范围后,蒟蒻觉得最短路可行。

代码思想

  • 输入后存储每一个点的横、纵坐标,然后把任意两个满足坐标非严格递增的点之间连一条边,并把边权值赋为xi-xj+yi-yj-1(xi>=xj,yi>=yj),此时相邻的两个点间的距离为0。
  • 然后以每个没有遍历过的点为端点,找这个点到其他点的最短路,最短路长即为需要添加的点的个数;
  • 按长度排序后从1到n循环,判断能不能通过添加k个点使得端点到该点相通,如果能,依次用该点与端点的横纵坐标之差+1再加上多余的k的值与当前的最大值比较,更新最大值。
  • 输出最大值。

~可以看代码注释帮助理解~。

代码贴在下面我知道你们只看这个

#include<bits/stdc++.h>
using namespace std;
#define N 2500005
#define inf 0x3f3f3f3f
long long n,k;
struct Point{//存储输入点的信息 
    long long x,y,id;
}a[505];
struct Edge{//链式前向星存图 
    long long v,w,next;
}tu[N];
struct Ans{//这里把dis写成结构体,方便排序(其实不用排) 
    long long id,w;
}dis[505];
long long head[N],ce,vis[505],vist[505];//vis存储一个点是否走过的信息,vist存储一个点有没有遍历过的信息,vis用于SPFA找最短路,vist用于找端点 
inline void adde(long long u,long long v,long long w){//链式前向星添加边 
    tu[++ce].v=v;tu[ce].w=w;tu[ce].next=head[u];
    head[u]=ce;
}
inline bool cmp(Ans x,Ans b){//自定义sort排序 
    return x.w>b.w;
}
long long ans=-1;//把最长上升点列的长初始化为1 
inline void SPFA(long long x){//SPFA找最短路 
    for(long long i=1;i<=n;i++){//每次找最短路的时候都要初始化dis和vis的值 
        dis[i].w=inf,dis[i].id=i;
        vis[i]=0;
    }
    queue<long long> q;//队列 
    dis[x].w=0;
    q.push(x);
    vis[x]=1;
    vist[x]=1;//初始化 
    while(!q.empty()){
        long long u=q.front();//每次获取队首元素 
        q.pop();//将队首元素弹出 
        vis[u]=0;
        for(long long i=head[u];i;i=tu[i].next){//遍历每一条相连的边 
            long long v=tu[i].v,w=tu[i].w;
            if(dis[v].w>dis[u].w+w){//三角形不等式更新最小值 
                dis[v].w=dis[u].w+w;
                if(!vis[v]){//判断这个点有没有走过 
                    q.push(v);//没有的话,更新为走过,并加入队列 
                    vis[v]=1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(dis[i].w!=inf&&i!=x&&k>=dis[i].w){//判断添加上k个点后,端点能到哪些点 
            vist[i]=1;//把这些点标记为非端点 
        }
    }
    sort(dis+1,dis+n+1,cmp);//排序(感觉不用排,有没有大佬知道需不需要排,可以写在评论区) 
    for(long long i=1;i<=n;i++){
        if(k>=dis[i].w) ans=max(ans,a[dis[i].id].x-a[x].x+a[dis[i].id].y-a[x].y+1+k-dis[i].w);//如果加上k个点后能到达这个点,更新上升点列的最大值 
    }
}
int main(){
    ios::sync_with_stdio(0);//cin,cout提速 
    cin>>n>>k;
    for(long long i=1;i<=n;i++){
        cin>>a[i].x>>a[i].y;
        a[i].id=i;  
    }
    for(long long i=1;i<=n;i++) 
        for(long long j=1;j<=n;j++){
            if(a[j].x>=a[i].x&&a[j].y>=a[i].y&&i!=j){//判断如果有两个点满足非严格递增,且不是这个点本身 
                adde(i,j,a[j].x-a[i].x+a[j].y-a[i].y-1);//加边 
            }
        }
    for(long long i=1;i<=n;i++){
        if(!vist[i]){//特判,每次找最短路只需要找端点,不加这一行的话会有两个点超时 
            SPFA(i);
        }
    }
    cout<<ans<<endl;//输出 
    return 0;
}

SPFA没有死

posted @   UncleSam_Died  阅读(53)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示