题一:

给定一个源区间[x,y]和N个无序的目标区间[x1,y1] [x2,y2] ... [xn,yn],判断源区间[x,y]是不是在目标区间内。


方法一

 先用区间的左边界值对目标区间进行排序O(nlogn),对排好序的区间进行合并O(n),对每次待查找的源区间,用二分查出其左右两边界点分别处于合并后的哪个源区间中O(logn),若属于同一个源区间则说明其在目标区间中,否则就说明不在。

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

struct Line
{
int low, high;
bool operator<(const Line &l) const
{return low<l.low;}
};

#define MAXN 10001
Line lines[MAXN]; // 目标区间
int ncnt = 0; // 合并后区间的个数

#define N 101
Line sl[N]; // 待查询的源区间

// 用二分查找找出key所在的区间,以区间的low作为划分
int GetIndex(int key)
{
int u, v;
u = 0; v = ncnt-1;
while (u<=v) // u,v可取等号
{
int m = (u+v)>>1;
if (key >= lines[m].low)
u = m+1;
else
v = m-1;
}
return v;
}

int main()
{
int n, k, i, j;
cin >> n >> k; // n是目标区间的个数,k是待查询的源区间的个数
for (i=0; i<n; i++)
cin >> lines[i].low >> lines[i].high;
for (i=0; i<k; i++)
cin >> sl[i].low >> sl[i].high;
// 排序O(nlogn)
sort(lines, lines+n);
// 合并O(n)
int lasthigh = lines[0].high;
for (i=1; i<n; i++)
if (lasthigh >= lines[i].low)
lasthigh = lines[i].high;
else
{
lines[ncnt++].high = lasthigh;
lines[ncnt].low = lines[i].low;
lasthigh = lines[i].high;
}
lines[ncnt++].high = lasthigh;
for (i=0; i<k; i++)
{
// 单词查找时间O(logn)
int s1 = GetIndex(sl[i].low);
int s2 = GetIndex(sl[i].high);
if (s1==s2 && sl[i].high <= lines[s2].high)
printf("Yes\n");
else
printf("No\n");
}
}


方法二


使用并查集,对每个区间合并到一个子树上,最后判断源区间的x和y的根是否相同。


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

const int len=100;
int father[len];

void make_set(){
for(int i=0;i<len;i++){
father[i]=i;
}
}

int find(int x){
int r=x;
while(r!=father[r]){
r=father[r];
}
int i=x;
while(i!=father[i]){
int j=father[i];
father[i]=r;
i=j;
}
return r;
}

void merge(int a,int b){
int ra=find(a);
int rb=find(b);
if(ra!=rb){
father[ra]=rb;
}
}


int main(void)
{
freopen("a.txt","r",stdin);
int x1,y1;
cin>>x1>>y1;
int n;
cin>>n;
make_set();
while(n--){
int x,y;
cin>>x>>y;
for(int i=x+1;i<=y;i++){
merge(x,i);
}
}

if(find(x1)==find(y1)){
cout<<"yes"<<endl;
}else{
cout<<"no"<<endl;
}


return 0;
}

时间复杂度比方法一高,思路简洁




题二


题目描述:请编写程序,找出下面“输入数据及格式”中所描述的输入数据文件中最大重叠区间的大小。
对一个正整数n,如果n在数据文件中某行的两个正整数(假设为A和B)之间,即A<=n<=B或A>=n>=B,则n属于该行;如果n同时属于行i和j,则i和j有重叠区间;重叠区间的大小是同时属于行i和j的整数个数。
 例如,行(10 20)和(12 25)的重叠区间为[12 20],其大小为9;行(20 10)和(12 18)的重叠区间为[10 18],其大小为9;行(20 10)和(20 30)的重叠区间大小为1。

输入数据:程序读入已被命名为input.txt的输入数据文本文件,该文件的行数在1到1,000,000之间,每行有用一个空格分隔的2个正整数,这2个正整数的大小次序随机,每个数都在1和2^32-1之间。(为便于调试,您可下载测试input.txt文件,实际运行时我们会使用不同内容的输入文件。)

输出数据:在标准输出上打印出输入数据文件中最大重叠区间的大小,如果所有行都没有重叠区间,则输出0。

评分标准:程序输出结果必须正确,内存使用必须不超过256MB,程序的执行时间越快越好。


将输入的区间按起点从小到大排列,然后对每个区间判断从当前区间起点到目前的right的距离,此距离即为覆盖距离。当覆盖距离大于最大覆盖时则更新最大覆盖。每次循环都要判断是否需要更新lastEnd,lastEnd表示目前此前所有区间的最大终点值。




#include<iostream>
#include<cstdio>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;

struct cmp{
bool operator()(const pair<int,int>& a,const pair<int,int>& b)const{
return a.first<b.first;
}
};


int main(){
ifstream in("a.txt");
vector<pair<int,int> >vec;
int a,b;
while(in>>a>>b){
if(a>b){
swap(a,b);
}
vec.push_back({a,b});
}

sort(vec.begin(),vec.end(),cmp());

int maxCover=0;
int lastEnd=vec[0].second;
int len=vec.size();
for(int i=1;i<len;i++){
int right=min(lastEnd,vec[i].second);
int cover=right-vec[i].first>=0?right-vec[i].first+1 : 0;
if(cover>maxCover){
maxCover=cover;
}
if(vec[i].second>lastEnd){
lastEnd=vec[i].second;
}
}

cout<<maxCover<<endl;

return 0;
}