• 贪心算法部分题目及知识点总结


    贪心算法部分题目总结:

    一:背包问题
    背包问题与最优装载问题十分类似,都是取优先级别级别最高或较高的变量进行处理,其中分为两种类型:变量(货物)可拆分/不可拆分两类;对于这两类类型,可以先将其性价比一一算出,先装性价比较高的,然后依次降低,直到背包装满货物,需要注意的一点就是比较,在快装满时比较出是否背包可全部装进该物品,若不可则进行分割或装入下一个能装进且性价比较高的物品(不可分割时)。(FATMOUSE’ TRADE看守仓库问题与之类似,也是寻找最优性价比问题)
    二:删数问题
    n位数中删去k位数,使得剩下的数字组成的整数最小。
    可以采取x[i+1]与x[i]比较,如果x[i+1]比较小的话,则删去x[i];
    当删去1位数字以后。原问题变成了对n-1位删去k-1位,有点像递归。
    三:多处最优服务次序问题
    设有n个顾客同时等待一项服务,顾客i需要的服务时间为ti,1≤i≤n,共有s处可以提供此项服务。应如何安排n个顾客的服务次序才能使平均等待时间达到最小?平均等待时间是n个顾客等待服务时间的总和除以n。
    对服务时间最短的顾客先服务的贪心选择策略。(使用贪心算法时)
    这道题类似于之前的接水问题,上次已经写到。
    四:moving tables
    在经理给出的说明表格中,已经明确地描述了算法:
    (从房间30到50)和(从房间60到90)是允许的,因为没有占用公共的走廊;
    (从房间20到40)和(从房间31到80)是不允许的,因为要占用公共的走廊。
    我们将每个房间之间的走廊作为一个统计单位,当所有的办公桌都搬运完成之后,看看这段走廊到底需要占用多少次?然后统计所有的走廊被占用的最大值max,这个值就是要单独安排的搬运次数,乘以10就是总的搬运时间。

    int i, j;
    int move[200];
    int N;        //搬运次数
    //每次搬运的起点和终点
    int from, to;
    scanf("%d", &N);
    memset(move, 0, sizeof(move));
    for(i = 0; i < N; i++)
    {
      scanf("%d%d", &from, &to);
      //将房间号映射为走廊号
      from = (from - 1)/2;
      to = (to - 1)/2;
      //确保from<to,C++使用:swap(from, to)
      if(from > to) {
        int temp = from; 
        from = to; 
        to = temp;
      }
      //占用走廊情况
      for(j = from; j <= to; j++)
        move[j]++;
    }
    //所有的走廊被占用的最大值
    int max = 0;
    for(i = 0; i < 200; i++)
      if(move[i] > max) max = move[i];
    printf("%d
    ", max * 10);
    

    五:均分纸牌
    有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若干张纸牌,然后移动。
    移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
    现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。例如 N=4,4 堆纸牌数分别为: ① 9 ② 8 ③ 17 ④ 6
    移动3次可达到目的:
    从 ③ 取4张牌放到④(9 8 13 10)->从③取3张牌放到 ②(9 11 10 10)-> 从②取1张牌放到①(10 10 10 10)。
    【输入格式】

    N(N 堆纸牌,1 <= N <= 100) 
       A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)
    

    【输出格式】

    所有堆均达到相等时的最少移动次数。
    

    【样例输入】Playcard.in

       4
        9 8 17 6 
    

    【样例输出】Playcard.out

       3
    

    这个题目要求我们考虑平均数问题,因为最终状态我们要得到每堆牌数都相等,在这个基础上我们可以简化一下问题,使该平均数为零,刚开始未移动的纸牌从这个基础上进行赋值变化,这时我们的目标就是使每堆纸牌数都变成零。

    cin>>n;
      ave=0;step=0; 
      for (i=1;i<=n;++i)
       {
        cin>>a[i]; ave+=a[i];              //读入各堆牌张数,求总张数ave
       } 
      ave/=n;                                          //求牌的平均张数ave
      for (i=1;i<=n;++i) a[i]-=ave;         //每堆牌的张数减去平均数
      i=1;j=n;
      while (a[i]==0&&i<n) ++i;            //过滤左边的0
      while (a[j]==0&&j>1) --j;              //过滤右边的0
      while (i<j)
       {
       a[i+1]+=a[i];                              //将第i堆牌移到第i+1堆中去
       a[i]=0;                                        //第i堆牌移走后变为0
       ++step;                                      //移牌步数计数 
       ++i;                                            //对下一堆牌进行循环操作
       while (a[i]==0&&i<j) ++i;          //过滤移牌过程中产生的0
       } 
      cout<<step<<endl; 
    

    六:整数区间  
    请编程完成以下任务:   
    1.读取闭区间的个数及它们的描述;   
    2.找到一个含元素个数最少的集合,使得对于每一个区间,都至少有一个整数属于该集合,输出该集合的元素个数。
    【输入】
       首行包括区间的数目n,1<=n<=10000,接下来的n行,每行包括两个整数a,b,被一空格隔开,0<=a<=b<=10000,它们是某一个区间的开始值和结束值。
    【输出】
       第一行集合元素的个数,对于每一个区间都至少有一个整数属于该区间,且集合所包含元素数目最少。
    【样例输入】

      4
      3 6
      2 4
      0 2
      4 7
    

    【样例输出】

    2
    

    我们先可以找到重复的元素,然后利用这个元素去一一排除多余的集合,当然我们可以通过排序来在最小集合的右端(最大值)进行一一查找,具体类似于下图:

    •算法模型:给n个闭区间[ai,bi], 在数轴上选尽量少的点,使每个区间内至少有一个点。
       •算法:首先按b1<=b2<=…<=bn排序。每次标记当前区间的右端点x,并右移当前区间指针,直到当前区间不包含x,再重复上述操作。
       •如下图,如果选灰色点,移动到黑色点更优。

    #include<iostream>
    using namespace std;
    int a[10001],b[10001],sum=0,n,m;
    void qsort(int x,int y)          //多关键字快排
    { 
      int i,j,mid1,mid2,t;
      i=x;j=y;mid1=b[(x+y)/2];mid2=a[(x+y)/2];
      while(i<=j)
       { while(b[i]<mid1||((b[i]==mid1)&&(a[i]<mid2)))  ++i;
         while(b[j]>mid1||((b[j]==mid1)&&(a[j]>mid2)))  --j;
         if(i<=j)
          { t=b[j];b[j]=b[i];b[i]=t;
            t=a[j];a[j]=a[i];a[i]=t;
            ++i;  --j; 
          }
       }
      if(x<j) qsort(x,j);
      if(i<y) qsort(i,y);
    }
    int main()
    {
      cin>>n;
      for(int i=1;i<=n;++i)cin>>a[i]>>b[i];
      qsort(1,n);
      for(int i=1,x=-1;i<=n;++i)    //在初始化循环变量的同时,初始化x。
                                                 //令x=-1可以使第一个区间与其他区间的操作
                                                   相同。
       {
           if (x>=a[i]) continue;      //如果当前区间包含标记点,就跳过。
           ++sum;   x=b[i];             //更新标记点。
        }
      cout<<sum<<endl;
      return 0;
    }
    

    stable_sort 和 sort的区别:
    stable_sort 和 sort的区别在于前者作排序可以使原来的"相同"的值在序列中的相对位置不变。这是稳定排序函数,当重量相同时,保持输入数据原来的顺序。
    如 1 4 6 7 4’ (4 和 4’值相等,加上’ 表示是2个元素)
    那么stable_sort能保证排序完 4 仍然在4’前也就是输出1 4 4’ 6 7;但是sort 没有这个功能,算法不能保证这一点。

  • 相关阅读:
    Oracle 手工清除回滚段的几种方法
    Oracle dump undo 说明
    Oracle ORA_ROWSCN 伪列 说明
    Oracle 10.2.0.4 高负载 触发 ORA00494 错误
    Oracle Block scn/commit scn/cleanout scn 说明
    Oracle 游标(cursor) 说明
    Oracle 10g Toad查看 表空间 报错 ORA00600 internal error code arguments [ktfbhget4], [6], [5]
    Oracle Block scn/commit scn/cleanout scn 说明
    Oracle 监听(Listener) 中 services 说明
    Oracle 游标(cursor) 说明
  • 原文地址:https://www.cnblogs.com/study-hard-forever/p/12130037.html
Copyright © 2020-2023  润新知