51nod 1563 坐标轴上的最大团(今日gg模拟第一题) | 线段覆盖 贪心 思维题

51nod 1563 坐标轴上的最大团

坐标轴上有n个点,每个点有一个权值。第i个点的坐标是 xi ,权值是 wi 。现在对这些点建图。对于点对 (i,j) ,如果 |xi−xj|≥wi+wj ,那么就给第i个点和第j个点之间连一条边。
问建好的图中最大团有几个点。
样例解释:

Input
单组测试数据。
第一行有一个整数n (1≤n≤200000),表示坐标轴上有n个点。
接下来n行,每一行有两个整数xi, wi (0≤xi≤109,1≤wi≤109),表示第i个点的坐标和权值。
所有的xi是不一样的。
Output
输出一个整数,表示最大团中有几个点。
Input示例
样例输入1
4
2 3
3 1
6 1
0 2
Output示例
样例输出1
3

把一个点表示为一个区间\([x_i - w_i, x_i + w_i]\),那么没有重合的两个线段之间就会有边,所以选则没有重合的最多线段就好——熟悉的线段覆盖!

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
bool read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
        else if(c == EOF) return 0;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
    return 1;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 200005;
int n, ans;
struct range{
    int l, r;
    bool operator < (const range &b) const{
        return r < b.r;
    }
} a[N];

int main(){
    read(n);
    for(int i = 1, x, w; i <= n; i++)
        read(x), read(w), a[i] = (range){x - w, x + w};
    sort(a + 1, a + n + 1);
    for(int i = 1, r = 0x80000000; i <= n; i++)
        if(a[i].l >= r) ans++, r = a[i].r;
    write(ans), enter;
    return 0;
}
posted @ 2017-10-16 14:57  胡小兔  阅读(370)  评论(0编辑  收藏  举报