枚举
三种思路:
1、开个数组,直接暴力让每个区域内的所有树对应位置置1,O(LxM),题目给的数据范围不大,不会TLE,代码如下:
#include <bits/stdc++.h>
using namespace std;
#define N 10010
int main(){
int a[N],L,M,rm,o_last,d_last;
cin>>L>>M;
rm = L + 1; //剩余树的数目
for(int j = 0;j <= N;j++) //初始化
a[j] = 0;
for(int i = 1;i <= M;i++){ //标记被覆盖的树
int temp_o,temp_d;
cin>>temp_o>>temp_d;
if(temp_o > temp_d) swap(temp_o,temp_d);
for(int j = temp_o;j <= temp_d;j++)
a[j] = 1;
}
for(int k = 0;k <= N;k++){ //遍历数组
rm -= a[k];
}
cout<<rm;
return 0;
}
2、考虑更大范围的数据,暴力枚举大概率会TLE,与标记的思路类似,记录每棵树被覆盖的次数,把区间问题转换成区间端点的问题,维护一个差分和数组即可(数组初始化为0,当某片区域被覆盖时仅需改变区间端点值即可实现区间所有值同时增大或减小),代码如下:
#include <bits/stdc++.h>
using namespace std;
#define N 10010
int delta[N];
int main(){
int a[N],L,M,rm = 0;
cin>>L>>M;
for(int i = 1;i <= M;i++){
int temp_o,temp_d;
cin>>temp_o>>temp_d;
if(temp_o > temp_d) swap(temp_o,temp_d);
//若区间左值比右值大,则交换
delta[temp_o]++; //维护差分和用来存储树被覆盖次数
delta[temp_d+1]--;
}
for(int k = 0;k <= L;k++){ //求差分和的前缀和还原原数组
if(k == 0) a[k] = delta[k];
else a[k] = delta[k] + a[k-1];
}
for(int m = 0;m <= L;m++) //数组中0元素的个数即为剩余树数目
if(a[m] == 0) rm++;
cout<<rm;
return 0;
}
3、进一步地,如果L范围较大,方法二中的数组空间需进一步扩大,可能会MLE,不妨先对区间左值进行排序,如果当前区间与上一个区间有交集,则生成一个新区间,此时区间右值为当前区间和上一个区间的右值的较大值;若无交集,则剩余树数目减去上一个区间长度+1,代码如下:
#include <bits/stdc++.h>
using namespace std;
#define N 110
struct ar{
int x,y;
}a[N];
bool comp(ar s,ar t){ //降序规则
if(s.x > t.x) return 0;
else return 1;
}
int main(){
int L,M,rm;
cin>>L>>M;
for(int i = 1;i <= M;i++){ //读入数据
cin>>a[i].x>>a[i].y;
if(a[i].x > a[i].y) swap(a[i].x,a[i].y);
}
rm = L+1;
sort(a+1,a+M+1,comp); //区间左值按升序排列
int temp_o = a[1].x,temp_d = a[1].y;
for(int j = 2;j <= M;j++){
//如果区间相交,则取区间右值中较大的那个数作为新区间右值
if(a[j].x <= temp_d)
temp_d = max(a[j].y,temp_d);
//如果区间不相交,则减去旧区间,生成新区间
else{
rm -= (temp_d-temp_o+1);
temp_o = a[j].x;
temp_d = a[j].y;
}
}
//最后一个区间记得减
rm -= (temp_d-temp_o+1);
cout<<rm;
return 0;
}