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校门外的树)的更多相关文章

  1. 区间重合判断[poj2808 校门外的树]

    题目:http://bailian.openjudge.cn/practice/2808/ 参考了文章,重写了代码:http://www.cnblogs.com/youxin/p/3266617.ht ...

  2. OpenJudge计算概论-校门外的树

    /*======================================================================== 校门外的树 总时间限制: 1000ms 内存限制: ...

  3. 【解题报告】VijosP1448校门外的树(困难版)

    原题: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的--如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r ...

  4. C语言 · 校门外的树

    算法提高 校门外的树   时间限制:1.0s   内存限制:256.0MB      问题描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的 ...

  5. 【洛谷】【线段树】P1047 校门外的树

    [题目描述:] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L ...

  6. NC16649 [NOIP2005]校门外的树

    NC16649 [NOIP2005]校门外的树 题目 题目描述 某校大门外长度为 \(L\) 的马路上有一排树,每两棵相邻的树之间的间隔都是 \(1\) 米.我们可以把马路看成一个数轴,马路的一端在数 ...

  7. P1047 校门外的树

    P1047 校门外的树 题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0 ...

  8. Vijos1448校门外的树 题解

    Vijos1448校门外的树 题解 描述: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现 ...

  9. [swustoj 764] 校门外的树 Plus Plus

    校门外的树 Plus Plus(0764) 问题描述 西南某科技大学的校门外长度为 L 的公路上有一排树,每两棵相邻的树之间的间隔都是 1 米.我们可以把马路看成一个数轴,马路的一端在数轴 1 的位置 ...

随机推荐

  1. ASP.NET jQuery 随笔 显示RadioButtonList成员选中的内容和值

    通过jQuery来获取RadioButtonList成员内容. <%@ Page Language="C#" AutoEventWireup="true" ...

  2. c++ enum用法【转】

    1.为什么要用enum       写程序时,我们常常需要为某个对象关联一组可选alternative属性.例如,学生的成绩分A,B,C,D等,天气分sunny, cloudy, rainy等等.   ...

  3. Linux相关问题-CentOS6.5 x64版本号下Tomcat无法自启动的解决的方法

    前段时间使用阿里云server.使用的是Linux CentOS6.5系统,在搭建完Tomcat后发现,Tomcat无法自启动. 将启动tomcat的命令为tomcat_home/bin/startu ...

  4. 数据科学家:神话 &amp; 超能力持有者

    一个打破神话的季节,正在降临.        我将坦诚地揭穿人们关于数据科学家所持有的惯有看法.在下文中,我将一个一个展示这些观点,宛如将一个又一个的玻璃瓶子摔碎在墙壁上一样.        关于数据 ...

  5. javascripts小结

    1 NAN-isNaN():判断是否数值 2 数值转换 Number()-任何数据类型,parseInt(),parseFloat()-字符串 3数组转字符串 var a=["red&quo ...

  6. spring多数据源的配置

    C3P0和DBCP的区别 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展.目前使用它的开源项目有Hibernate,Spring等.   d ...

  7. 关于android的坑

    坑1: 使用SQLiteOpenHelper的时候如果建立的表中存在不为空的字段,但是用ContentValues()的方式来插入数据的话恰好没有往这个字段里插入数据,那么执行后市没法往数据库里插入数 ...

  8. (Problem 22)Names scores

    Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-tho ...

  9. Qt下如何修改文件的时间(全平台修改)

    提供一个全平台修改文件的时间的方法,希望大家喜欢 /* UTIME.C: This program uses _utime to set the * file-modification time to ...

  10. 「JAVA」:Berkeley DB的JAVA连接

    Berkeley DB是一个嵌入式的数据库,它适合于管理海量的.简单的数据.关键字/数据(key/value)是Berkeley DB用来进行数据管理的基础.每个key/value构成了一条记录,而整 ...