clique 解题报告

clique

题目描述

数轴上有 (n) 个点,第 (i) 个点的坐标为 (x_i),权值为 (w_i)。两个点 (i),(j) 之间存在一条边当且仅当 (abs(x_i-x_j)>=w_i+w_j)。你需要求出这张图的最大团的点数。(团就是两两之间有边的顶点集合)

输入数据

第一行一个整数 (n),接下来 (n) 行每行两个整数 (x_i,w_i)

输出数据

一行一个整数表示答案

数据范围

对于 (20\%) 的数据, (n<=10)
对于 (60\%) 的数据, (n<=1000)
对于 (100\%) 的数据, (n<=200000)(0<=|x_i|,w_i<=10^9)


考试的时候发现了一个性质

如果三个点按从左到右排,点1点2有边且点2点3右边可以得到点1点3有边

于是可以(N^2)连边跑topo最长路(从左到右连有向边)

想拿(set)优化连边但是没想到。

结果数组开小爆30了。

正解算是没想到吧。

如果把点看做形如([x-w,x+w])的区间,那么两个点有连边等价于区间无交点。

于是问题转化成了不重合的区间数量

可以简单的贪心,也可以DP

复杂度都是(O(nlogn))


Code:

#include <cstdio>
#include <algorithm>
const int N=2e5+10;
struct node
{
    int l,r;
    bool friend operator <(node n1,node n2){return n1.r<n2.r;}
}seg[N];
int rr[N],dp[N],f[N],pos[N],n;
int max(int x,int y){return x>y?x:y;}
int main()
{
    scanf("%d",&n);
    for(int x,w,i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&w);
        seg[i].l=x-w,seg[i].r=x+w;
        rr[i]=seg[i].r;
    }
    std::sort(seg+1,seg+1+n);
    std::sort(rr+1,rr+1+n);
    rr[0]=seg[1].r-1;
    for(int i=1;i<=n;i++)
    {
        int l=0,r=i-1;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(seg[i].l>=rr[mid])
                l=mid;
            else
                r=mid-1;
        }
        pos[i]=l;
    }
    for(int i=1;i<=n;i++)
        dp[i]=f[pos[i]]+1,f[i]=max(f[i-1],dp[i]);
    printf("%d
",f[n]);
    return 0;
}


2018.10.13

原文地址:https://www.cnblogs.com/butterflydew/p/9784029.html