题目
有 n 条线段。
每条线段给定其中一端的位置及长度。
求所有线段覆盖的最大长度。
n≤100。
思路
先按端点排序
设
f
i
,
j
,
0..1
f_{i,j,0..1}
fi,j,0..1 表示前
i
i
i 条线段,最靠右的是第
j
j
j 条,其方向为0或1
考虑如何转移,从小到大枚举
i
i
i 后面的线段以及它的方向,同时维护枚举过的线段中最靠右的线段以及它的方向。
设线段 j j j 在 p p p 方向的右端点是 o o o;此时枚举到线段 k k k,它的方向为 q q q,长度为 l l l,右端点是 t t t;枚举过的线段中最靠右的线段是 x x x,它的方向为 y y y,右端点是 z z z。
则有转移:
f
k
,
x
,
y
=
f
i
,
j
,
p
+
m
i
n
(
l
,
t
−
o
)
+
z
−
t
f_{k,x,y}=f_{i,j,p}+min(l,t-o)+z-t
fk,x,y=fi,j,p+min(l,t−o)+z−t
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
const int N=107;
int n,ans,f[N][N][2];
pii a[N];
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d%d",&a[i].fi,&a[i].se);
sort(a+1,a+n+1);
a[0].fi=-1e9;
for(int i=0; i<=n; i++) for(int j=0; j<=i; j++) for(int p=0; p<2; p++)
{
ans=max(ans,f[i][j][p]);
int yjy=a[j].fi+p*a[j].se,mx=-1e9,x,y;
for(int k=i+1; k<=n; k++) for(int q=0; q<2; q++)
{
int t=a[k].fi+q*a[k].se;
if(t>mx) mx=t,x=k,y=q;
f[k][x][y]=max(f[k][x][y],f[i][j][p]+min(a[k].se,t-yjy)+mx-t);
}
}
printf("%d",ans);
}