贪心算法之区间调度问题
问题主题:区间调度问题
问题描述:
有n项工作,每项工作分别在si开始,ti结束。对每项工作,你都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,即参与工作的时间段不能有重叠(即使开始的时间和结束的时间重叠都不行)。
限制条件:
1<=n<=100000
1<=si<=ti,=109
样例:
输入
n=5
s={1,2,4,6,8}
T={3,5,7,9,10}
输出
问题描述:
有n项工作,每项工作分别在si开始,ti结束。对每项工作,你都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,即参与工作的时间段不能有重叠(即使开始的时间和结束的时间重叠都不行)。
限制条件:
1<=n<=100000
1<=si<=ti,=109
样例:
输入
n=5
s={1,2,4,6,8}
T={3,5,7,9,10}
输出
3(选择工作1, 3, 5)
对这个问题,如果使用贪心算法的话,可能有以下几种考虑:
(1)、每次选取开始时间最早的;
(2)、每次选取结束时间最早的;
(3)、每次选取用时最短的;
(4)、在可选工作中,每次选取与最小可选工作有重叠的部分;
对于上面的四种算法,只有算法(2)是正确的,其它的三种都可以找到相应的反例。具体证明如下:
数轴上有n个区间,选出最多的区间,使得这些区间不互相重叠。
算法:
将所有区间按右端点坐标从小到大排序,顺序处理每个区间。如果它与当前已选的所有区间都没有重叠,则选择该区间,否则不选。
代码如下:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int MAXN=100000; pair<int,int> itv[MAXN]; int main() { int i,j,n,s[MAXN],t[MAXN],tt=0,ans=0;//tt是所选工作的结束时间 scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d",&s[i]); } for(j=0;j<n;j++) { scanf("%d",&t[j]); } sort(itv,itv+n); for(i=0;i<=n;i++)//为了让结束时间早的工作排在前面,把t存在first,s存在second { itv[i].first=t[i]; itv[i].second=s[i]; } for(i=0;i<n;i++) { if(tt<itv[i].second) { ans++; tt=itv[i].first; } } cout<<ans<<endl; return 0; }