线段区间的覆盖

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

举例:给出M=61,2,4,5,7,11,分别表示6个长度为1的区间,要求用不超过N=3条线段将其覆盖。

线段区间的覆盖问题

上图给出了一种可行的覆盖方案,用三段长线段覆盖住6个长度为1的小线段,使得3短线段长度之和最小。

l  算法思想

运用贪心算法,M个线段会产生M-1个间断,间断有大有小,按照从大到小的顺序把线段间的间隔排好。假设初始状态下有一整条线段覆盖整个区域,每一步都从间隔最大的位置上断开该线段,直至断开N-1次,此时一整条线段就被分成了N截且这N截线段的长度和最小。

l  程序模型的建立与设计流程

如果N>=M,显然用M条长度为1的线段就可覆盖所有区间,所求的线段总长度也就为M。如果N,要另想办法。

①  N=1,那么所需线段总长为position[M-1]-position[0]+1;

②  N=2,那么相当于把①中的长线段分成两截。找到最大距离distance[i]=position[i]-position[i-1]-1 (1

③  N=3,同理,将distance第二大的位置断开,于是便形成3截线段,并且长度和最小。

④  N=k(k>1)时,只要在N=k-1时最小总长的覆盖方案下,找到被同一条线段覆盖最大的两个区间,“贪心”地从间隔处断开并适当调整两条线段的端点,就可以得到总长最小的方案。

l  数据结构的选用

可用整型数组position[M]表示所有的区间,并假设position[M]已按从小到达的顺序排好了。

l  源程序编码清单

#include

using namespace std;

const int SIZE=200;

 

void Sort(int value[],int nNumber)              //nNumber个值从大到小排列

{

       for(int i=0;i

              for(int j=0;j

                     if(value[j]

                     {

                            int temp=value[j];

                            value[j]=value[j+1];

                            value[j+1]=temp;

                     }

}

void main()

{

       int M=0;

       int position[SIZE];

       cout<<"请输入待覆盖的区间总数M="<<endl;

       cin>>M;

       int i=0;

       cout<<"请具体地输入第"<<M

              <<"个要覆盖的区间:"<<endl;

       for(i=0;i

       {

              cin>>position[i];

       }

       Sort(position,M);

 

       int distance[SIZE-1];

       for(i=0;i

              distance[i]=position[i]-position[i+1]-1;

       Sort(distance,M-1);

 

       int N=1;                                     //可用于覆盖的线段总数

       cout<<"请输入可用于覆盖的线段总数N="<<endl;

       cin>>N;

//**********贪心算法*************************

       if(N>=M)

       {

              cout<<"最小的线段总长为"

                     <<M<<endl;

              return;                           

       }

 

       else if(N

       {

              int nLine=1;                           //记录当前线段总数

              int nTotalLength=position[0]-position[M-1]+1;//记录当前情况下所用线段的总长

              int nDivide=0;                         //记录当前最大的未断开的区间位置

              while((nLine0]))

              {

                     nLine++;

                     nTotalLength-=distance[nDivide];

                     nDivide++;

              }

              cout<<"最小的线段总长为"

                     <<nTotalLength<<endl;

       }

}

l  程序输入、输出

线段区间的覆盖问题

l  时间与空间复杂度分析

算法时间复杂度为O(nlogn)+O(n)。

l  程序使用说明

①  对position的排序无论从大到小还是从小到大没有区别,不影响区间距离的计算。

②  注意while循环的两个条件

l  总结与完善

这个程序可以得到最小总长条件下所需的最少线段的数目,但并不能给出这些线段的端点信息。可以进一步对程序修改以添加此功能。

原文地址:https://www.cnblogs.com/bytebull/p/5733956.html