题目大意
原题
给出n个时间段(开始时间和结束时间),从中选择几个不重合的时间段,使得所有时间段加起来最大。
解题思路
由于时间段不能重合,并且输入不是按顺序排的,所以直接做会导致漏掉需要选择的时间段或选择了不需要选择的时间段,因此要先按结束时间排序。
其次我们再考虑设
f
i
f_i
fi为前
i
i
i个时间段能获得的时间,对于一个时间段,如果不选,则时间不会改变,所以不选的值是
f
i
f_i
fi;如果选,那么就需要枚举它的上一个时间段
j
j
j,并且第
i
i
i个时间段的开始时间必须小于或等于第
j
j
j个时间段的结束时间,否则会导致时间段的重合,因此,我们可以推出
f
i
=
m
a
x
(
f
i
,
f
j
+
t
i
,
2
−
t
i
,
1
)
f_i=max(f_i,f_j+t_i,_2-t_i,_1)
fi=max(fi,fj+ti,2−ti,1)
注意:
j
j
j的结束时间
≤
i
\le i
≤i的开始时间,并且在dp时要边做边取,因为最后取得的
f
n
f_n
fn不一定是最优解,而是当选择最后一场的最优解。
初始化:
f
[
i
]
=
t
i
,
2
−
t
i
,
1
f[i]=t_i,_2-t_i,_1
f[i]=ti,2−ti,1。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int ans,f[3005],n;
struct ap{
int l,r;
}t[1005];
bool cmp(ap a,ap b)
{
return a.l<b.l;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>t[i].l>>t[i].r;
sort(t+1,t+n+1,cmp);//按结束时间排序
for(int i=1;i<=n;i++)
f[i]=t[i].r-t[i].l;
for(int i=1;i<=n;i++)//枚举i
for(int j=1;j<i;j++)//枚举i要在哪一场之后举行
if(t[i].l>=t[j].r)//如果时间不重合
{
f[i]=max(f[i],f[j]+t[i].r-t[i].l);
ans=max(ans,f[i]);//边做边取,最后得到的f[n]可能不是正解
}
cout<<ans;
return 0;
}