简单的区间覆盖问题

问题描述:用i表示x轴上坐标为[i-1,i]的区间(区间长度为1),并给出M个不同的整数来表示M个这样的区间。现在要求画出几条线段覆盖住所有的区间,条件是:每条线段可任意长,但要求所画线段长度之和最小,并且线段的数目不超过N

分析
    1) 整型数组p[M]表示所有从0开始的区间长度,假设p[M]已经
按从小到大的顺序排好


    2) 如果N>=M,
那么用 M条长度为 1 的线段可以覆盖住所有的区间,所求的线段总长为 M;


3)如果N<M,可以按照如下的贪心准则解决:


① 如果N=1,即要用一条线段覆盖住所有区间。


      线段总长:p[M-1]-p[0]+1。


bb


其中:p[0]=1  ,  p[1]=3  ,   p[2]=4 , ……,p[M-1]=M--区间总长度


② 如果N=2,即要用 2 条线段覆盖住所有区间,相当于把N=1中的线段分为两部分,各覆盖左、右区间。


如果线段在M个区间中不相邻的区间之间断开(如在p[0]与p[1]之间),这样总长度小于断开之前。【不相邻的很多怎么办?】


线段总长度减少: p[1]-p[0]-1


cc


回顾我们的题目要求:求最小线段总长。



找到间隔最大的两个相邻区间,将之断开。


   这一过程相当于找:d[i]=p[i]-p[i-1]-1(1<i<M)的最大值



如果N=3,相当于在N=2的方案下,将某条线段断成两截,并作可能的端点调整。


为了得到当前情况下最小的总长度,同样应该在间隔最大的两个相邻区间之间断开


    如果原来的方案是N=2时总长最小的方案,这一操作是N=3时总长最小的方案。



当N=k(k>1)时依此类推,只需在N=k-1时最小总长的覆盖方案下,找到被同一条线段覆盖的间隔最大的两个相邻区间


------“贪心”地从间隔处断开并调整两边线段的端点,就可以得到总长最小的方案



贪心策略就是每次从找到当前间隔最大的相邻区间

例题

用i来表示x坐标轴上坐标为[i-1,i]的长度为1的区间,并给出N(1≤N≤200)个不同的整数,表示N个这样的区间。

现在要求画m条线段覆盖住所有的区间,
条件是:每条线段可以任意长,但是要求所画线段的长度之和最小,
并且线段的数目不超过N。
 

输入

 输入包括多组数据,每组数据的第一行表示点n,和所需线段数m,后面的n行表示点的坐标

输出

 输出每组输出占一行表示线段的长度。

示例输入

5 3
1 3 5 8 11

示例输出

7

代码

#include <iostream>
#include <algorithm>
using namespace std;
int a[1000];
int s[1000];
int cmp(int a,int b)
{
  return a>b;
}
int main()
{
    int n,m;
    int len;
    int sum;
    while(cin>>n>>m)
    {
     for(int i=0;i<=n-1;i++)
     {
      cin>>a[i];
     }
     sort(a,a+n);
     len=a[n-1]-a[0]+1;
     for(int i=0;i<n-1;i++)//求区间的间隔距离
     {
      s[i]=a[i+1]-a[i]-1;
     }
     sort(s,s+n-1,cmp);
     sum=len;
     for(int i=0;i<m-1;i++)
     {
      sum=sum-s[i];
     }
    cout << sum << endl;
    }
    return 0;
}


整个过程说白了就是排序,没啥。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值