CF545C Woodcutters(贪心)题解
贪心算法两句话
第一句话:
能往左倒就往左倒。
如同数学中“我们不妨设”一样,相信很好理解。这里只对第二句话稍作解释:
不能往左倒的尽量往右倒
这样为什么是对的呢?
我们可以分类讨论一下:
-
假设当前已经处理到第\(i\)个,且它不能往左倒,\(h_i\)表示树高,\(x_i\)表示位置。
-
若\(x_{i + 1} - x_i > h_i\),也就是说i可以往右倒,那么它有两种选择:
-
往右倒。如果倒完以后\(i+1\)还能向左倒,那么显然最优;如果倒完之后\(i+1\)不能往左倒了,
那么在处理\(i+1\)时会考虑它能否往右,但我们发现\([i-i + 1]\)这段区间内的贡献已达到了最大值(因为就算让\(i + 1\)往左倒这段区间对答案贡献也为\(1\)),因此不会使答案变差。
-
不往右倒。假如\(i + 1\)既能往左倒又能往右倒,那么如果\(i\)不往右倒就会影响答案,所以不能选。
-
-
若\(x_{i + 1} - x_i \leq h_i\),也就是说不能往右倒,这时它根本没得选。
综上,我们证明了该贪心算法的正确性,希望这对你有所帮助。
贴一波代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int n,ans;
struct Tree{
int h,x;
}t[maxn];
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i) scanf("%d%d", &t[i].x, &t[i].h);
ans = 2;
for(int i = 2; i < n; ++ i){
if(t[i].x - t[i - 1].x > t[i].h) ans ++;
else if(t[i + 1].x - t[i].x > t[i].h) ans ++, t[i].x += t[i].h;
} printf("%d\n", ans);
return 0;
}