CF545C Woodcutters
题意翻译
给 n 棵树在一维数轴上的坐标,以及它们的长度。现在要你砍倒 这些树,树可以向左倒也可以向右倒,砍倒的树不能重合、当然 也不能覆盖其他的树原来的位置,现在求最大可以砍倒的树的数 目。 1 <= n <= 10^5 ; 1 <= x i , h i <= 10^9
感谢@凉凉 提供的翻译
题解:
一眼切的DP。
看到很多大佬都是用的贪心解法。所以来介绍一下DP。
DP的精髓在于转移。所以状态的设置要为转移服务。转移要保证无后效性和最优子结构。DP就是这些东西,再也没有什么其他的了。什么答案的统计都是细节问题。
那么这道题显然,针对于两棵树之间的转移,一定有第(i)棵树不砍、往左砍、往右砍这三种状态,每种状态都会对应一个最优决策,所以就直接按这个设状态:(dp[i][0/1/2])。
然后按题意转移就行。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,dp[maxn][3];
struct tree
{
int x,h;
}t[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&t[i].x,&t[i].h);
dp[1][0]=1;
if(t[2].x-t[1].x>t[1].h)
dp[1][1]=1;
for(int i=2;i<=n;i++)
{
dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
if(t[i].x-t[i-1].x>t[i-1].h)
dp[i][0]=max(dp[i][0],dp[i-1][2]);
if(t[i].x-t[i-1].x>t[i].h)
dp[i][1]=max(dp[i-1][1]+1,dp[i-1][0]+1);
if(t[i].x-t[i-1].x>t[i].h+t[i-1].h)
dp[i][1]=max(dp[i][1],dp[i-1][2]+1);
dp[i][2]=max(dp[i-1][0],dp[i-1][1])+1;
if(t[i].x-t[i-1].x>t[i-1].h)
dp[i][2]=max(dp[i][2],dp[i-1][2]+1);
}
cout<<max(max(dp[n][0],dp[n][1]),dp[n][2]);
return 0;
}