天天看点

wikioi-天梯-普及一等-贪心-1214:线段覆盖

题目描述 Description

    给定x轴上的N(0<N<100)条线段,每个线段由它的二个端点a_I和b_I确定,I=1,2,……N.这些坐标都是区间(-999,999)的整数。有些线段之间会相互交叠或覆盖。请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段两两之间没有内部公共点。所谓的内部公共点是指一个点同时属于两条线段且至少在其中一条线段的内部(即除去端点的部分)。

输入描述 Input Description

    输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。

输出描述 Output Description

    输出第一行是一个整数表示最多剩下的线段数。

样例输入 Sample Input

3

6  3

1  3

2  5

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

0<N<100

类型:贪心  难度:1.5

题意:见上述

分析:又考虑多了的一道题。。

先将线段排序,先按线段起点排序,若起点相同按终点排序,都是由小到大,依次遍历线段判断是否保留。

设当前线段为[ai,bi],之前保留的线段的最右边的点为now,考虑以下情况:

1、ai>=now,即当前线段和之前保留的线段不重叠,那么直接保留当前线段(ans++),更新now=bi

2、ai<now,当前线段和之前保留的线段有重叠,再分情况考虑:

(1)若bi<=now,证明当前线段完全被之前保留线段的区域包含(因为已经排序,所以当前线段的起点一定大于等于之前的线段,bi<now证明终点小于等于之前线段,所以被包含),那么证明当前线段更优(一条线段被另一条完全包含,显然取短的线段更优,即贪心),更新now=bi,但是结果计数(ans)不变

(2)若bi>now,证明当前线段一部分和之前重叠,一部分不重叠,那么为了对后续线段影响最小,即now尽量小,用贪心法则,当前线段被舍弃,结果计数(ans)不变

ps:开始用sort排序,发现sort无法直接对二维数组排序,所以用qsort排序了

代码:

#include<iostream>
#include<algorithm>
using namespace std;

int cmp(const void *x,const void *y)
{
    int *a = (int*)x,*b = (int*)y;
    if(a[0]==b[0]) return a[1]-b[1];
    return a[0]-b[0];
}

int main()
{
    int n,ave=0,a[110][2];
    cin>>n;
    for(int i=0; i<n; i++)
    {
        int l,r;
        cin>>l>>r;
        if(l<r) 
        {
            a[i][0] = l;
            a[i][1] = r;
        }
        else
        {
            a[i][0] = r;
            a[i][1] = l;
        }
    }
    qsort(a,n,sizeof(int)*2,cmp);
    /*
    for(int i=0; i<n; i++)
    {
        cout<<a[i][0]<<" "<<a[i][1]<<endl;
    }*/
    int ans = 1,now = a[0][1];
    for(int i=1; i<n; i++)
    {
        if(a[i][0]>=now)
        {
            ans++;
            now = a[i][1];
        }
        else
        {
            if(a[i][1]<now) now = a[i][1];
        }
    }
    
    cout<<ans<<endl;
}