【基础算法】万圣节大礼包

题目大意

平面上有n个点,从原点出发,每次的路径长度要严格小于上一次,求能访问的点的最大值(可以重复访问)


分析

将边按照边权排序,从大到小依次处理,这样就可以满足处理某条边时,之前的边都可以访问,
设当前处理的边的两个端点分别为 x,yx<y
maxi(i) 表示以i为终点的路径最大值。
不难得到 maxi(x)=max(maxi(x),maxi(y)+1)
同理, maxi(y)=max(maxi(y),maxi(x)+1)

接下来有两个问题:
1、这样得到的答案是从任意一点出发,而题目要求从原点出发
2、对于权值相同的边,计算会出问题(严格小于)

对于问题1,我们加几个特判即可:(设原点为0号点)
maxi(x)=0,x0maxi(y) ,y也同理。
x=0 ,那么 maxi(y)=max(maxi(y),1)

对于问题2,只需要用类似于滚动的方法来处理即可(详见代码)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 2010
using namespace std;
int maxi[MAXN],maxir[MAXN],cnt,n,len[MAXN*MAXN];
pair<int,int> a[MAXN*MAXN],l[MAXN];
vector<int> up;
long long squ(long long x){
    return x*x;
}
long long lenth(int x,int y){
    return squ(l[x].first-l[y].first)+squ(l[x].second-l[y].second);
}
bool cmp(pair<int,int> x,pair<int,int> y){
    return lenth(x.first,x.second)>lenth(y.first,y.second);
}
int main(){
    SF("%d",&n);
    for(int i=1;i<=n;i++)
        SF("%d%d",&l[i].first,&l[i].second);
    for(int i=0;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            a[++cnt]=make_pair(i,j);
    sort(a+1,a+1+cnt,cmp);
    for(int i=1;i<=cnt;i++)
        len[i]=lenth(a[i].first,a[i].second);
    for(int i=1;i<=cnt;i++){
        int u=a[i].first;
        int v=a[i].second;
        if(len[i]!=len[i-1]){
            for(int j=0;j<up.size();j++)
                maxi[up[j]]=max(maxi[up[j]],maxir[up[j]]);
            up.clear();
        }
        up.push_back(u);
        up.push_back(v);
        if(u==0){
            maxir[v]=max(maxi[v],1);
            continue;
        }
        if(maxi[u]!=0)
            maxir[v]=max(maxir[v],maxi[u]+1);
        if(maxi[v]!=0)
            maxir[u]=max(maxir[u],maxi[v]+1);

    }
    for(int j=0;j<up.size();j++)
        maxi[up[j]]=max(maxi[up[j]],maxir[up[j]]);
    up.clear();
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,maxi[i]);
    PF("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值