区间重合判断(pojg校门外的树)
pojg;http://poj.grids.cn/practice/2808
解法1:以空间换时间:
#include<stdio.h>
#include<string.h>
int main()
{
int L,M;
scanf("%d%d",&L,&M);
bool *a=new bool[];
memset(a,,sizeof(bool)*); int m,n;
for(int i=;i<=M;i++)
{
scanf("%d%d",&m,&n);
for(int j=m;j<=n;j++)
{
a[j]=false;
}
}
int sum=;
for(int i=;i<=L;i++)
{
if(a[i]==true)
sum++;
}
printf("%d\n",sum);
}
2:合并区间):
思想是将所有区间存储在数组里面,对所有区间以下限为标准排序,然后从头至尾扫描区间数组,
合并区间的方法是:当前区间初始化为第一个区间,然后判断下一个区间的下限是否已经超过当前区间的上限,如果是这样的话,就无法继续合并了,那么就继续已经合并区间的长度,重新开始一次新的合并,否则的话,将下一个区间合并到当前区间起来。。。
#include<stdio.h>
#include<stdlib.h>
typedef struct Line{
int start;
int end;
}Line; int compareLine(const void *a,const void *b)
{
return ((Line *)a)->start-((Line *)b)->start;
}
int main()
{
Line line[],tmp;
int L,M;
scanf("%d%d",&L,&M); for(int i=;i<M;i++)
{
scanf("%d%d",&line[i].start,&line[i].end);
}
qsort(line,M,sizeof(Line),compareLine); int count=;
tmp=line[];
for(int i=;i<M;i++)
{
if(line[i].start<=tmp.end)
{
tmp.end=line[i].end;
}
else
{
count=count+tmp.end-tmp.start+;
tmp=line[i];
}
}
count=count+tmp.end-tmp.start+1;//为什么 printf("%d\n",L+-count);
}
我们以(1,2) (2,4) (4,5) (6,7) (9,12)
开始tmp=line[0].
i=1 合并 tmp.end=4;
i=2 合并 tmp.end=5;
i=3; count=0+ (5-1)+1=5; tmp=line[3];
i=4; tmp.end<line[4].start; count=5+(7-6)+1=7; tmp=line[4];
退出
count=7+(12-9)+1=11;
参考:http://www.cppblog.com/csu-yx/archive/2011/11/07/159746.html
如果L很大,比如是40亿,无法开辟这么大的数组,怎么办?采用第二种方法可以。
编程之美也有类似的这个题目,其实,种树问题本质是区间重合判断。
一,问题:
1. 给定一个源区间[x,y]和N个无序的目标区间[x1,y1] [x2,y2] ... [xn,yn],判断源区间[x,y]是不是在目标区间内。
2. 给定一个窗口区域和系统界面上的N个窗口,判断这个窗口区域是否被已有的窗口覆盖。
第一题源代码:
按照编程之美给出的提示。 先用区间的左边界值对目标区间进行排序O(nlogn),对排好序的区间进行合并O(n),对每次待查找的源区间,用二分查出其左右两边界点分别处于合并后的哪个源区间中O(logn),若属于同一个源区间则说明其在目标区间中,否则就说明不在。(为什么可以二分法)
#include<iostream>
#include<algorithm>
using namespace std; #define MAX 10001
struct Line
{
int low,high;
bool operator<(const Line &L) const
{
return low<L.low;
}
}; Line lines[MAX]; // 目标区间
int ncount=;//合并后区间个数 //用二分查找找出key所在的区间,以区间的low作为划分
int getIndex(int key)
{
int u,v;
u=;
v=ncount-;
while(u<=v) //记住=
{
int m=(u+v)>>;
if(key>=lines[m].low)
u=m+;
else
v=m-;
}
return v; } int main()
{ int n;//目标区间个数
cout<<"输入目标区间个数"<<endl;
cin>>n;
cout<<"输入目标区间"<<endl;
for(int i=;i<n;i++)
{
cin>>lines[i].low>>lines[i].high;
cout<<endl;
}
cout<<"输入源区间个数"<<endl;
int k;
cin>>k;
Line source[];
for(int i=;i<k;i++)
{
cin>>source[i].low>>source[i].high;
cout<<endl;
}
//排序O(nlgn)
sort(lines,lines+n);
int tmp=lines[].high;
for(int i=;i<n;i++)
{
if(tmp>=lines[i].low)
{
tmp=lines[i].high;
}
else
{
lines[ncount++].high=tmp;
lines[ncount].low=lines[i].low;
tmp=lines[i].high;
}
}
lines[ncount++].high=tmp; for(int i=;i<k;i++)
{
int s1=getIndex(source[i].low);
int s2=getIndex( source[i].high);
if(s1==s2 && source[i].high<=lines[s2].high)
{
cout<<"在区间内"<<endl;
}
else
{
cout<<"不再区间内"<<endl;
}
} }
上面的程序有点错误:
在if (lasthigh >= lines[i].low)
lasthigh = lines[i].high;
不能直接修改lasthigh值,要判断if(lasthigh<lines[i].high)才能修改 如{1,5}{2,4}则会合并成{1,4}.
转自:http://blog.csdn.net/tianshuai1111/article/details/7828961
下面的程序好点:
#include <iostream>
#include <algorithm>
using namespace std; struct Line{
int low,high;
Line(int l=,int h=):low(l),high(h){}
bool operator<(Line & other)
{
return low<other.low;
}
}; const int MAX = ;
Line lines[MAX]; //注意咱们搜索的数为刚好小于key的那个值
int BinarySearchLower(Line arr[],int len,int target)
{
int low = ;
int high = len-; while(low < high){
int mid = (low + high)/;
if(arr[mid].low>=target)high = mid-;
else low = mid + ; }
return high;
} int main()
{
int n, k, i, j; cin>>n; // n是目标区间的个数,k是待查询的源区间的个数
for (i=; i<n; i++)
cin >> lines[i].low >> lines[i].high; sort(lines, lines+n); int cnt = ; //合并以后的区间数
int lasthigh = lines[].high; //合并区间
for(i=; i<n; i++){
if(lasthigh>=lines[i].low && lasthigh<lines[i].high)
lasthigh = lines[i].high;
else{
lines[cnt].high = lasthigh;
lines[++cnt].low = lines[i].low;
lasthigh = lines[i].high;
} }
lines[cnt++].high = lasthigh; Line search = Line(,); int sLow = BinarySearchLower(lines,cnt,search.low);
int sHigh = BinarySearchLower(lines,cnt,search.high);
if(sLow==sHigh && search.high<=lines[sLow].high)//注意要判断
cout<<"Yes"<<endl;
else cout<<"No"<<endl; system("pause");
return ;
}
我们输入三段目的区间:
1 4
2 3
7 8
要查找的是1-5,
经过合并后lines变成了:
1 4
2 3
78
注意2,3并没有去掉,在查找的时候有用。
上面的程序有问题。
解法:使用并查集
对每个区间合并到一个子树上,最后判断源区间的x和y的根是否相同。
#include<iostream>
using namespace std; const int size = ;
int father[size];
int rank[size]; void make_set(int n)
{
for(int i = ; i <= n; i ++){
father[i] = i;
rank[i] = ;
}
} int find_set(int x)//寻找代表元素
{
if(x != father[x]){ //元素不是单独的段,在某个区间内,返回某个区间代表
father[x] = find_set(father[x]);
}
return father[x];
} void Union(int x, int y)
{
x = find_set(x);
y = find_set(y); if(x == y){ //两个在同一个区间
return ;
} if(rank[x] < rank[y]){
father[x] = y;
}
else{
father[y] = x;
if(rank[x] == rank[y]){
rank[x] ++;
}
}
} int main()
{
int x1, y1;
cin >> x1 >> y1;//输入要判断区间
int x, y;
int n;
cin >> n; //区间的个数
make_set(size);
while(n --){
cin >> x >> y; //输入每个区间
if(x > y){//这一步很关键,表示考虑的周到
swap(x, y);
}
for(int i = x + ; i <= y; i++){//将区间内的 段合并到已有区间
Union(x, i);
}
}
if(find_set(x1) == find_set(y1)){
cout << "yes" << endl;
}
else{
cout << "no" << endl;
}
system("pause");
}
更多:http://blog.csdn.net/tianshuai1111/article/details/7828961
画图理解:
区间重合判断(pojg校门外的树)的更多相关文章
- 区间重合判断[poj2808 校门外的树]
题目:http://bailian.openjudge.cn/practice/2808/ 参考了文章,重写了代码:http://www.cnblogs.com/youxin/p/3266617.ht ...
- OpenJudge计算概论-校门外的树
/*======================================================================== 校门外的树 总时间限制: 1000ms 内存限制: ...
- 【解题报告】VijosP1448校门外的树(困难版)
原题: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的--如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r ...
- C语言 · 校门外的树
算法提高 校门外的树 时间限制:1.0s 内存限制:256.0MB 问题描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的 ...
- 【洛谷】【线段树】P1047 校门外的树
[题目描述:] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L ...
- NC16649 [NOIP2005]校门外的树
NC16649 [NOIP2005]校门外的树 题目 题目描述 某校大门外长度为 \(L\) 的马路上有一排树,每两棵相邻的树之间的间隔都是 \(1\) 米.我们可以把马路看成一个数轴,马路的一端在数 ...
- P1047 校门外的树
P1047 校门外的树 题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0 ...
- Vijos1448校门外的树 题解
Vijos1448校门外的树 题解 描述: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现 ...
- [swustoj 764] 校门外的树 Plus Plus
校门外的树 Plus Plus(0764) 问题描述 西南某科技大学的校门外长度为 L 的公路上有一排树,每两棵相邻的树之间的间隔都是 1 米.我们可以把马路看成一个数轴,马路的一端在数轴 1 的位置 ...
随机推荐
- 以程序的方式操纵NTFS的文件权限(陈皓)
http://blog.csdn.net/haoel/article/details/2905 http://blog.sina.com.cn/s/blog_7f91494101018nmn.html
- perl5 第八章 子程序
第八章 子程序 by flamephoenix 一.定义二.调用 1.用&调用 2.先定义后调用 3.前向引用 4.用do调用三.返回值四.局部变量五.子程序参数传递 1.形式 2 ...
- Java中String、StringBuilder以及StringBuffer
原文出处: 海子 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String.StringBuilder和StringBuffe ...
- JAVA ThreadPoolExecutor(转)
原文链接:http://blog.csdn.net/historyasamirror/article/details/5961368 基础 在我看来,java比C++的一个大好处就是提供了对多线程的支 ...
- 变脸不变质的桥梁模式(Bridge Pattern)
有一哥们是搞山寨货的,什么流行就搞什么.自己有个厂子,前些时间服装挣钱,就生产衣服,如今搞手机挣钱,搞手机,这哥们非常聪明,就换了个产品,工人,厂房都不变.他是怎么做到的?用类图来模拟一下: 由类图能 ...
- Lamd表达式
1. 普通绑定: public void button1_Click(object sender, EventArgs e) { MessageBox.Show("ok"); } ...
- [Asp.net]常见word,excel,ppt,pdf在线预览方案(转)
引言 之前项目需要,查找了office文档在线预览的解决方案,顺便记录一下,方便以后查询. 方案一 直接在浏览器中打开Office文档在页面上的链接.会弹出如下窗口: 优点:主流浏览器都支持. 缺点: ...
- CSS3属性值之box-shadow
语法: box-shadow:inset x-offset y-offset blur-radius spread-radius color 也就是: 对象选择器 {box-shadow:投影 ...
- Enze fourth day(循环语句 一)
哈喽,大家好.又到了总结知识的时间了.今天在云和学院自学了一下循环语句,下面是自己总的一些知识点. 先补充一下选择结构中的switch语句. 理论:switch语句是一种多分支选择语句,当需要测试大量 ...
- 这些屌炸天的创业者为何对投资人说NO
曾有人说,世上的创业者只分为两种,一种是找到投资的,一种是没有找到的. 但其实还有第三种,就是那些拒绝了投资人的创业者. 他们摒弃了投资人抛来的橄榄枝,并非不差钱,不接受投资的原因大体出于两个方面,一 ...