时间限制:1.0s 内存限制:256.0MB
关键字:区间处理
问题描述
  某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
  由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入格式
  输入文件的第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点 和终止点的坐标。
输出格式
  输出文件包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
样例输入
500 3
150 300
100 200
470 471
样例输出
298
数据规模和约定
  对于20%的数据,区域之间没有重合的部分;
  对于其它的数据,区域之间有重合的情况。
【分析】由于马路的端点都有树,则L长的马路边一共有L+1棵树,如果当成L棵树的话,答案就会比原来的少了1,这是我刚开始犯的错误,又认真审题才发现,细节问题很重要,首先定义一个二维数组用来存储地铁区域s[l, r],也就是要移走的区间,每个区间里包含 count 棵树, count = (r - l +1)
1.先把区间按照左端点为依据进行排序,当左端点相等时,依据右端点升序排列
2.判断下一区间的左端点和当前区间的右区间的大小进行比较,可能会包含三种情况
第一种:两区间没有交集,则需要移走的数目count = count1 + count2
第二种:下一区间被当前区间所包含,这时移走的树木不变
第三种:下一区间和当前区间重合一部分,这时count = count + 下一区间的右端点 - 当前区间的右端点
最后输出为(L+1-count)
【参考代码】
C++:

#include<stdio.h>
#include<algorithm>
using namespace std;
struct Area
{
    int l, r;
};
Area a[101];
bool cmp(Area a, Area b)
{
    return a.l < b.l;
}
int main()
{
    int L, m, i;
    scanf("%d%d", &L, &m);
    for(i = 0; i < m; i++)
        scanf("%d%d", &a[i].l, &a[i].r);
    sort(a, a+m, cmp);
    int tot = 0, crt = -1;
    for(i = 0; i < m; i++)
    {
        if(a[i].l > crt)
        {
            crt = a[i].l;
            tot++;
        }
        if(crt < a[i].r)
        {
            tot += a[i].r - crt;
            crt = a[i].r;
        }
    }
    printf("%d\n", L-tot+1);
    return 0;
}

c:

#include<stdio.h>
typedef struct
{
int start;
int end;
int flag;
}extent;
int main()
{
int L,M,i,j;
extent e[101];
scanf("%d%d",&L,&M);
for(i=1;i<=M;i++)
{
scanf("%d%d",&(e[i].start),&(e[i].end));
e[i].flag=1;
for(j=1;j<i;j++)
{
if(!(e[i].end<e[j].start||e[i].start>e[j].end)&&e[j].flag)
{
e[j].flag=0;
if(e[i].start>e[j].start)
e[i].start=e[j].start;
if(e[i].end<e[j].end)
e[i].end=e[j].end;
}
}//调整区间 
}
for(i=1;i<=M;i++)
if(e[i].flag)
L=L-(e[i].end-e[i].start+1);
printf("%d",L+1);
return 0;
}

Java:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int m = input.nextInt();
        int n = input.nextInt();
        int[] a = new int[2 * n];

        int d = 0, e, max;
        for (int i = 0; i < n; i++) {
            a[i] = input.nextInt();
            a[i + n] = input.nextInt();

        }
        max = a[0];
        for (int j = 0; j < 2 * n; j++) {
            if (max < a[j]) {
                max = a[j];
            }

        }
        int[] c = new int[max*10];
        for (int i = 0; i < n; i++) {
            for (int j = a[i]; j <=a[i + n]; j++) {
                c[j] = 1;
            }
        }
        for (int i = 0; i < max; i++) {
            if (c[i] == 1) {
                d = d + 1;

            }
        }
        e = m  - d;

        System.out.println(e);

    }

}

下面是我自己的思路写的Java实现的算法,思路很清晰,或许会有点麻烦:

import java.util.Scanner;

public class 校门外的树 
{
    public static void main(String[] args) 
    {
        Scanner sc = new Scanner(System.in);
        int L = sc.nextInt();//马路的长度
        int n = sc.nextInt(); //有多少个区域
        int[][] arr = new int[n][2]; //创建二维数组,存储区域的端点
        for (int i=0; i<n; i++)
        {
            for (int j=0; j<2; j++)
            {
                arr[i][j] = sc.nextInt();
            }
        }
        //依据左端点 对区域进行升序处理
        int temp = 0;
        for (int i=0; i<n; i++)
        {
            for (int j=i; j<n; j++)
            {
                if (arr[i][0] > arr[j][0])
                {
                    temp = arr[j][0];
                    arr[j][0] = arr[i][0];
                    arr[i][0] = temp;

                    temp = arr[j][1];
                    arr[j][1] = arr[i][1];
                    arr[i][1] = temp;
                }
                //当左端点相同时,依据右端点排序
                else if (arr[i][0] == arr[j][0])
                {
                    if (arr[i][1] > arr[j][1])
                    {
                        temp = arr[j][1];
                        arr[j][1] = arr[i][1];
                        arr[i][1] = temp;
                    }
                }
            }           
        }
        //进行计数处理
        int count = arr[0][1] - arr[0][0] + 1; //初始化等于第一段区域需要移走的树木
        //判断下一区域与当前区域的端点关系
        for (int i=0; i<n-1; i++)
        {
            if (arr[i+1][0] > arr[i][1])  //无交集
            {
                count += arr[i+1][1] - arr[i+1][0] + 1;
            }
            else if (arr[i+1][0] == arr[i][1])  //相接
            {
                count += arr[i+1][1] - arr[i+1][0];
            }
            else //有交集
            {
                if (arr[i+1][1] > arr[i][1])
                {
                    count += arr[i+1][1] - arr[i][1];
                }
                else //包含时不做处理,如果升序完成之后,这一步好像是多余的
                    continue;               
            }
        }
        System.out.println(L + 1 - count);
    }
}