线段覆盖区间选点区间覆盖贪心讲解
Posted kongbursi-2292702937
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段覆盖区间选点区间覆盖贪心讲解相关的知识,希望对你有一定的参考价值。
一、贪心引入:
最少硬币
有1、2、5、10、20、50、100七种面值的硬币,要支付指定的金额,问怎么支付所用的硬币个数最少。
这是一个非常日常化的问题,马上我们会想到,尽可能先用大面值的硬币,就能使支付的硬币尽可能少。这就是“贪心选择”。
二、贪心——线段覆盖
描述
学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办。小刘的工作就是安排学校小礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想尽可能的安排更多的活动,请问他该如何安排。
输入
第一行是一个整型数m(m<100)表示共有m组测试数据。
每组测试数据的第一行是一个整数n(1<n<10000)表示该测试数据共有n个活动。
随后的n行,每行有两个正整数Bi,Ei(0<=Bi,Ei<10000),分别表示第i个活动的起始与结束时间(Bi<=Ei)
输出
对于每一组输入,输出最多能够安排的活动数量。
输入样例 1
2 2 1 10 10 11 3 1 10 10 11 11 20
输出样例 1
1 2
题解:
就是给你了一些活动的时间,你需要在规定时间范围内举行最多的活动(举行活动的数量要最大)
这个时候有一些活动要开展的时间长一点,有一些活动开展时间短一点,这个时候我们可以首先按照每一个活动得终止时间进行从小到大排序。
排序完之后只有一个这一个时间内活动结束了才可以进行下一个活动,而终止时间就可以限制我们之后选择的活动开始时间必须大于它。我们要保证每一个活动开展时间不能太长,所以当结束时间一样的时候就要按照它的开始时间从大到小排序。
排序完之后,第0号位置的活动我们必须举行。之后的活动和我们之前选的活动(这个时候是0号活动)相比较,如果之后活动开始时间要大于0号活动,那就确认了下一个要举行的活动是它。之后的活动再与这个活动进行比较
示例解析:
3
1 10
10 11
11 20
排序后:
1 10
10 11
11 20
第0号活动必选,之后让第一号活动和第0号活动比较。因为第一号活动开始时间不大于第0号终止时间。所以此活动不举行
和第二号活动比较,第二号活动开始时间大于第0号终止时间。所以第二号活动举行。且之后活动要去和第二号活动比较
循环结束!输出答案2
代码:
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 struct node 6 { 7 int s; 8 int e; 9 } v[10005]; 10 bool cmp(node a,node b) 11 { 12 if(a.e==b.e) 13 { 14 return a.s>b.s; 15 } 16 return a.e<b.e; 17 } 18 int main() 19 { 20 int n,t,m,i,x,sum; 21 scanf("%d",&t); 22 while(t--) 23 { 24 scanf("%d",&n); 25 sum=1; 26 for(i=0; i<n; i++) 27 { 28 scanf("%d %d",&v[i].s,&v[i].e); 29 } 30 sort(v,v+n,cmp); 31 x=v[0].e; 32 for(i=1; i<n; i++) 33 { 34 if(v[i].s>x) 35 { 36 sum++; 37 x=v[i].e; 38 } 39 } 40 printf("%d ",sum); 41 } 42 return 0; 43 }
三、贪心——区间选点
描述
上数学课时,老师给了LYH一些闭区间,让他取尽量少的点,使得每个闭区间内至少有一个点。但是这几天LYH太忙了,你们帮帮他吗?
输入
多组测试数据。
每组数据先输入一个N,表示有N个闭区间(N≤100)。
接下来N行,每行输入两个数a,b(0≤a≤b≤100),表示区间的两个端点。
输出
输出一个整数,表示最少需要找几个点。
输入样例 1
4 1 5 2 4 1 4 2 3 3 1 2 3 4 5 6 1 2 2
输出样例 1
1 3 1
区间选点的话,我们可以以区间头来先排序。也可以先对区间尾进行排序。这里说对区间尾进行排序:
对区间尾进行从小到大排序,如果区间尾相同,我们可以对区间头任意排序,当然也可以不排序。
排序完之后0号区间是肯定要在里面建一个点,之后的区间和它(目前是0号)进行比较。如果之后的区间与这个区间有交集那就不需要添加新的点。否则就必须添加一个点且之后的比较要和这个新的区间进行比较
样例解析:
4
1 5
2 4
1 4
2 3
排序后:
2 3
1 4
2 4
1 5
第0号区间必选,之后第一号区间1 4和第0号区间有重叠部分,所以不用加点。第二号区间也和第0号区间有重叠部分,所以也不用加点。第三号区间也是如此
所以最后答案是1
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 using namespace std; 5 struct node 6 { 7 int s,e; 8 }a[10005]; 9 bool cmp(node a,node b) 10 { 11 if(a.e==b.e) 12 { 13 return a.s>b.s; 14 } 15 return a.e<b.e; 16 } 17 int main() 18 { 19 int n; 20 while(~scanf("%d",&n)) 21 { 22 for(int i=0;i<n;i++) 23 { 24 scanf("%d",&a[i].s); 25 scanf("%d",&a[i].e); 26 } 27 sort(a,a+n,cmp); 28 int ans=1,t=0; 29 for(int i=1;i<n;i++) 30 { 31 if(a[i].s>a[t].e) 32 { 33 ans++; 34 t=i; 35 } 36 } 37 printf("%d ",ans); 38 } 39 return 0; 40 }
四、区间覆盖
题目(本题原题目)
题目(另外一道题)
Sample Input
3 10 1 7 3 6 6 10
Sample Output
2
可以先对区间头进行从小到大排序,在区间头一样的情况下我们要对区间尾从大到小排序。因为我们要保证我们选择的每一头牛工作时间尽可能地长
0号牛可以说我们一定会使用它,之后的牛如果和0号牛的工作时间有交集那我们就要从这些有交集的牛上面找出来工作终止时间最大的那个
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 struct node 7 { 8 int s; 9 int e; 10 } a[25010]; 11 bool cmp(node a,node b) 12 { 13 if(a.s==b.s) 14 return a.e>b.e; 15 return a.s<b.s; 16 } 17 int main() 18 { 19 int n,m; 20 scanf("%d%d",&n,&m); 21 for(int i=0;i<n;++i) 22 { 23 scanf("%d%d",&a[i].s,&a[i].e); 24 } 25 sort(a,a+n,cmp); 26 if(a[0].s!=1) 27 { 28 printf("-1 "); 29 return 0; 30 } 31 int ans=1,k=a[0].e,ke=0; 32 for(int i=1;i<n;++i) 33 { 34 if(a[i].s>k+1) 35 { 36 ans++; 37 k=ke; 38 } 39 if(a[i].s<=k+1) 40 { 41 ke=max(ke,a[i].e); 42 if(ke==m) 43 { 44 k=ke; 45 ans++; 46 break; 47 } 48 } 49 } 50 if(k==m) printf("%d ",ans); 51 else printf("-1 "); 52 return 0; 53 }
以上是关于线段覆盖区间选点区间覆盖贪心讲解的主要内容,如果未能解决你的问题,请参考以下文章