区间重合判断(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 的位置 ...
随机推荐
- Android 百度地图开发问题----解决地图有时候加载不出来问题
相信很多人在开发百度地图的时候会出现百度地图有时候会加载不出来,只显示网格图. 这个问题究其原因就是申请百度key的时候填写的SHA1也就是指纹证书有问题.估计很多开发者都是照着百度开放平台上介绍的流 ...
- BZOJ 3402: [Usaco2009 Open]Hide and Seek 捉迷藏
题目 3402: [Usaco2009 Open]Hide and Seek 捉迷藏 Time Limit: 3 Sec Memory Limit: 128 MB Description 贝 ...
- Flex的学习资源
学习网站 http://www.adobe.com/cn/devnet/flex.html Adobe Flex开发人员中心 http://www.adobe.com/cn/devnet/flex/v ...
- 74HC595的中文资料
74HC595--具有三态输出锁存功能的8位串行输入.串行/并行输出移位寄存器 本文翻译自NXP的74HC595的datasheet 74HC595和74HCT595是带有存储寄存器和三态输出的8位串 ...
- iOS --- [持续更新中] iOS移动开发中的优质资源
在我们做iOS APP的开发过程中, 须要非常多设计, 产品, 技术, 运营等方面的技巧和资源. 现将其整理汇总, 本文会一直持续更新. 敬请关注. 设计 Dribbble Dribbble是一个面向 ...
- Android中图片处理相关问题
在Android的开发中,我们经常回去处理一些图片相关的问题,比如当加载图片到内存中产生的OOM(OutOfMemory)异常.图片加载到内存中占多大内存的问题.jpg png两种常见的图片的原理及区 ...
- FreeCodeCamp:Return Largest Numbers in Arrays
要求: 右边大数组中包含了4个小数组,分别找到每个小数组中的最大值,然后把它们串联起来,形成一个新数组. 提示:你可以用for循环来迭代数组,并通过arr[i]的方式来访问数组的每个元素. 结果: l ...
- vim 多文件编辑【超实用】
vim 多文件编辑(偶的linux笔记) http://blog.csdn.net/lcj_cjfykx/article/details/18805721 通过vim打开的每个文件都对应着一个buff ...
- NSUserDefaults概述
原创,转载请注明原文:NSUserDefaults概述 By Lucio.Yang 首先,iOS中有四种存储数据的方式-对比iOS中的四种数据存储 NSUserDefaults是其中很常用的一种.N ...
- Log4J logger图片