【题目链接】
ybt 1323:【例6.5】活动选择
洛谷 P1803 凌乱的yyy / 线段覆盖
注意:ybt 1323数据个数最大为
1
0
3
10^3
103, 洛谷P1803数据个数最大为
1
0
6
10^6
106
【题目考点】
1. 贪心
2. 贪心选择性质的证明
要想证明贪心选择可以得到最优解,只需要证明最优解包含每一次的贪心选择。
使用数学归纳法:
- 证明最优解包含第一次的贪心选择
- 假设存在最优解包含前k次的贪心选择,证明该最优解包含第k+1次的贪心选择
【解题思路】
1. 贪心选择性质的证明:
贪心选择:每次选择不与已选择活动重叠的结束时间最早的活动
- 证明:存在最优的活动选择方案包含第一次贪心选择:结束时间最早的活动g
- 证明:在k次贪心选择后,存在最优的活动选择方案包含第k+1次的贪心选择:不与前面重叠的结束时间最早的活动g。
2. 具体做法
用结构体对象存储各个活动的开始和结束时间。按活动的结束时间对活动进行升序排序。顺序取各个活动,只要该活动与前一个选择的活动不重叠(即该活动的起始时间不早于已经选择的最后一个活动的结束时间),那么就选择该活动。统计活动数量。
【题解代码】
解法1:贪心
注意:ybt 1323中,数组长度N可以设为1005, 洛谷P1803数组长度N必须设为1000005
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int b[N], e[N];
struct Act
{
int begin, end;
};
Act act[N];
bool cmp(Act a, Act b)
{
return a.end < b.end;
}
int main()
{
int n, actNum = 0, lastAct = 0;//lastAct:当前已经选择的活动中最后一个活动
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d %d", &act[i].begin, &act[i].end);
sort(act+1, act+1+n, cmp);//按照结束时间从小到大排序
for(int i = 1; i <= n; ++i)
{
if(act[i].begin >= act[lastAct].end)//如果第i个活动在当前最后的活动后面开始
{
actNum++;//选择第i活动 活动数量加1
lastAct = i;
}
}
printf("%d", actNum);
return 0;
}