CodeForces 545C - Woodcutters(贪心)
题目链接 https://cn.vjudge.net/problem/CodeForces-545C
【题意】
无限长的数轴上有n个点,每个点的坐标为x[i],种有高度为h[i]的树,现在要把一些树砍到,被砍倒的树要么倒向左边,要么倒向右边,会分别把[xi - hi, xi] 和 [xi,xi + hi]占用,如果某棵树不被砍倒,那么它就只占用x[i]这一个点的位置,现在给定你n个点的x[i],h[i],问最多能砍倒几棵树?(n<=1e5, x[i],h[i]<=1e9)
【思路】
贪心问题,很关键的地方在于对于某个区间[xi,x(i+1)]来说,这段区间要么被xi利用,要么被x(i+1)利用,要么被它们两个都利用,要么都不用,只有这四种可能。所以n个点把数轴划成了n+1个区间,我们从左往右依次枚举这n+1个区间即可,尽可能地让这些区间占用更多的树即可
#include<bits/stdc++.h>
using namespace std;
const int inf=2e9;
const int maxn=100050;
int n;
bool used[maxn];
struct node{
int x,h;
bool operator<(const node& e)const{
return x<e.x;
}
}tree[maxn];
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d%d",&tree[i].x,&tree[i].h);
}
sort(tree,tree+n);
int ans=0;
for(int i=0;i<=n;++i){//枚举n+1段路
if(0==i){//最左边的路放tree[0]
used[0]=1;
++ans;
continue;
}
if(n==i && !used[n-1]){//如果最右边的树没着落,那就放到最右边的路上
used[n-1]=1;
++ans;
continue;
}
int le= tree[i-1].x;
int ri= tree[i].x;
if(used[i-1]){//左边的树已经搞定了,只考虑当前的树就可以,能放就放
int len=ri-le;
if(len>=tree[i].h+1) { used[i]=1; ++ans; }
}
else{//左边的树还没着落,能都放下就都放下,放不下优先考虑放左边的
int len=ri-le+1;
if(len>=tree[i-1].h+1 + tree[i].h+1){
used[i-1]=used[i]=1;
ans+=2;
}
else if(ri-le>=tree[i-1].h+1){
used[i-1]=1;
++ans;
}
else if(ri-le>=tree[i].h+1){
used[i]=1;
++ans;
}
}
}
printf("%d\n",ans);
return 0;
}