时间限制: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);
}
}