【C - 区间覆盖】贪心算法

题意:

数轴上有 n个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t],不可能办到输出-1。

思路:

定义一个结构体代表区间,在读入数据后,对数据进行多关键字排序(第一是左端点小的在前,第二是右端点大的在前)。对数据进行过滤,左端点相同的区间只保留区间长度最大的,如果当前区间被之前保留的区间完全包含则去掉。

如果数组中第一个区间不包含1即不可能包含[1,t],直接返回-1。

定义一个变量point表示将需要覆盖的下一个点,即[point,t]还未被覆盖。当point<=t时,进行循环。比较当前区间的左端点值与point的大小,分三种情况:

<1>相等,表明当前区间应该被选,更新point,继续比较和循环。
<2>区间端点的左值较大,看上一个区间(该区间左端点的值一定小于等于point)。如果上一个区间的右端点值与当前区间的左端点值相差大于1,即不相接,说明所给的区间至少不能覆盖 [上一区间右端点,当前区间左端点] ,返回-1;
否则,上一个区间符合条件,应该被选,更新point,继续比较和循环。
<3>point较大,如果当前区间已经是最后一个区间,选择当前区间,如果选上之后还是不能覆盖t点,则返回-1,如果能,则循环结束。若不是最后一个区间,则接着循环判断下一个区间。

总结:

过滤区间是有必要的,没有用的区间会造成复杂的情况,并且增大时间代价。

在循环过程中,需要考虑到所有的情况,最好是根据某些值进行分类以免造成冗余或者缺失。

代码:

#include
#include
using namespace std;
struct section
{
 int left;
 int right;
};
bool com(section a, section b)//左端点小的在前,右端点大的在前
{
 if (a.left != b.left)
  return a.left < b.left;
 if (a.right != b.right)
  return a.right > b.right;
}
int main()
{
 int n, t;
 scanf("%d %d", &n, &t);
 section* sec = new section[n];
 for (int i = 0; i < n; i++)
  scanf("%d %d", &sec[i].left, &sec[i].right);
 sort(sec, sec + n, com);
 if (sec[0].left != 1)//不能覆盖区间左端点1
 {
  printf("-1");
  return 0;
 }
 section* only = new section[n];
 int left = sec[0].left;
 int right = sec[0].right;
 only[0] = sec[0];
 int r = 1;
 for (int i = 1; i < n; i++)//如果左区间相同保留右区间最大的一个,一个区间被另一个区间包含时不加入
 {
  if (sec[i].left > t)//超出要覆盖区间
   break;
  if (sec[i].left == left|| sec[i].right<=right)
   continue;
 else//新的左区间值
  {
   only[r] = sec[i];
   left = sec[i].left;
   right = sec[i].right;
   r++;
  }
 }
 int sum = 0;//记录已选择的区间数目
 int point = 1;//[point,t]还没覆盖
 int i = 0;//标记数组位置
 while (point <= t)//未覆盖t
 {
  if (only[i].left == point)
  {
   point = only[i].right + 1;
   sum++;
   i++;
  }
  else if (only[i].left > point)//选择only[i-1]
  {
   if (only[i].left - only[i - 1].right > 1)//上一个区间接不住
   {
    printf("-1");
    return 0;
   }
   sum++;
   point = only[i - 1].right + 1;
  }
  else
  {
   if (i == r - 1)
   {
    sum++;
    point = only[i].right + 1;
    if (point <= t)
    {
     printf("-1");
     return 0;
    }
    break;
   }
   else
    i++;
  }
 }
 printf("%d", sum)}

你可能感兴趣的:(c++,贪心算法)