区间重合判断、百度之星题解之重叠区间大小

来源:互联网 发布:php日志系统 编辑:程序博客网 时间:2024/06/05 19:53

题一:

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


方法一

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

http://blog.csdn.net/tianshuai1111/article/details/7828961#comments

#include <iostream>#include <algorithm>using namespace std;struct Line{int low, high;bool operator<(const Line &l) const{return low<l.low;}};#define MAXN 10001Line lines[MAXN];// 目标区间int ncnt = 0;// 合并后区间的个数#define N 101Line 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;elsev = 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");elseprintf("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;}




0 0
原创粉丝点击