zoukankan      html  css  js  c++  java
  • 线段覆盖、区间选点、区间覆盖贪心讲解

    一、贪心引入:

    最少硬币

    有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 }
    View Code

    三、贪心——区间选点

    题目

    描述

     

    上数学课时,老师给了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 }
    View Code

    四、区间覆盖

    题目(本题原题目)

    题目(另外一道题)

    农夫约翰正在指派他的N头牛(1 <= N <= 25,000)中的一些来做谷仓周围的清洁工作。他总是希望有一头奶牛来做清洁工作,他把一天分成了T班(1 <= T <= 1,000,000),第一个是1班,最后一个是T班。
    每头奶牛只能在一天中的某个时段进行清洁工作。任何被选来做清洁工作的奶牛将在她的整个休息期间工作。
    你的工作是帮助农民John安排一些奶牛轮班,这样(i)每个轮班至少安排一头奶牛,(ii)清洁的奶牛越少越好。如果无法为每个班次分配一头奶牛,请打印-1。

    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 }
    View Code
  • 相关阅读:
    String substring(int start,int end)截取当前字符串中指定范围内的字符串
    String字符串是不变对象,内容一旦创建不可改变,若改变一定会创建新对象
    StringBuilder修改字符串内容,增,删,改,插
    startsWith(),endsWith()判断当前字符串是否是以给定字符串开始或结尾的
    length()返回当前字符串的字符个数
    indexOf()字符位置
    charAt()检测回文
    手把手教你猜字小游戏
    release 和 drain
    c专家编程 ,c语言运行时环境
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11778750.html
Copyright © 2011-2022 走看看