https://codeforces.com/problemset/problem/527/D
题目描述
数轴上有 nn 个点,第 ii 个点的坐标为 x_ixi,权值为 w_iwi。两个点 i,ji,j 之间存在一条边当且仅当 abs(x_i-x_j)\geq w_i+w_jabs(xi−xj)≥wi+wj 。 你需要求出这张图的最大团的点数。
团的定义:两两之间有边的顶点集合。
输入格式
第一行一个整数 nn,接下来 nn 行每行两个整数 x_i,w_ixi,wi 。
输出格式
一行一个整数表示答案。
感谢@Asougi_Kazuma 提供的翻译。
感谢@皎月半洒花 将翻译改成了正常人能看明白的翻译。
输入输出样例
输入 #1复制
4 2 3 3 1 6 1 0 2
输出 #1复制
3
说明/提示
If you happen to know how to solve this problem without using the specific properties of the graph formulated in the problem statement, then you are able to get a prize of one million dollars!
The picture for the sample test.
题目注意:这个团中两两都是有连边的才能是一个团。
思路:首先对绝对值进行拆分。
如果一个点对(i,j)满足|xi - xj| ≥ wi + wj 则在i,j之间连边
那么有
xi-xj>=wi+wj xi-wi>=xj+wj
xj-xi>=wi+wj xj-wj>=xi+wj(这个式子与上式等效)所以分析上面一个一样。
令Xi=xi-wi,Yj=xj+wj--->也就是说如果Xi>=Yj,就可以连边。现在把这个Xi的值看成一个端点值,Yj的值看成一个端点值。
那么样例模拟下来大致是
|________|(Yj)
(Xi)|__________|
|________|
之类的。
问题就转化成求怎么选使得最多有多少个区间没有交界。那么这就是个区间贪心的经典问题。
对区间坐标按Y去从小到大排序,如果有Xi>Y,那么ans++,同时更新Y的最大值。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+100;
typedef long long LL;
struct node{
LL x,y;
}nodes[maxn];
bool cmp(node A,node B){
if(A.y==B.y) return A.x<B.x;
return A.y<B.y;
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n;cin>>n;
for(LL i=1;i<=n;i++){
LL a,b;cin>>a>>b;
nodes[i].x=a-b;nodes[i].y=a+b;
}
sort(nodes+1,nodes+1+n,cmp);
LL Y=nodes[1].y;LL ans=1;
for(LL i=1;i<=n;i++){
if(nodes[i].x>=Y){
ans++;
Y=nodes[i].y;
}
}
cout<<ans<<endl;
return 0;
}