程式設計之美2 19 區間重合判斷(線段樹)

2021-06-20 19:03:22 字數 3502 閱讀 7989

問題:

1. 給定乙個源區間[x,y]和n個無序的目標區間[x1,y1] [x2,y2] ... [xn,yn],判斷源區間[x,y]是不是在目標區間內。

2. 給定乙個視窗區域和系統介面上的n個視窗,判斷這個視窗區域是否被已有的視窗覆蓋。

1. 解法:

先用區間的左邊界值對目標區間進行排序o(nlogn),對排好序的區間進行合併o(n),對每次待查詢的源區間,用二分查出其左右兩邊界點分別處於合併後的哪個源區間中o(logn),若屬於同乙個源區間則說明其在目標區間中,否則就說明不在。

[cpp]view plain

copy

"font-size:18px;"

>#include 

#include 

using

namespace

std;  

struct

line  

;  #define maxn 10001

line lines[maxn];   // 目標區間

intncnt = 0;       

// 合併後區間的個數

#define n 101

line sl[n];         // 待查詢的源區間

// 用二分查詢找出key所在的區間,以區間的low作為劃分

intgetindex(

intkey)  

return

v;  

}  int

main()  

lines[ncnt++].high = lasthigh;  

for(i=0; i  }

2. 解法:

這個問題適合使用線段樹來解答,單次查詢的時間複雜度為o(nlogn),當然也能用陣列解答,但單次查詢的時間複雜度會增加到o(n^2)。這裡我們直接使用線段樹來解答。

線段樹是一棵二叉樹,將數軸劃分成一系列的初等區間[i, i+1] (i=1,2,..,n-1)。每個初等區間對應於線段樹的乙個葉結點。線段樹的內部結點對應於形如[ i,  j ](j – i > 1)的一般區間。

由於線段樹給每乙個區間都分配了結點,利用線段樹可以求區間並後的總長度與區間並後的線段數。先給出測試資料(前4行是系統介面上已有的n個視窗,之後的一行是待測試的視窗區域),後面是**: 4

-15 0 5 10

-5 8 20 25

15 -4 24 14

0 -6 16 4

2 15 10 22

[cpp]view plain

copy

#include 

#include 

#include 

using

namespace

std;  

// 線段樹的結點

struct

segnode  

};  

// 構造線段樹,它是乙個完全二叉樹

void

buildsegtree(segnode *&tree, 

int*index, 

intlow, 

inthigh)  

}  }  // 往線段樹中插入線段,即用線段(low,high)來覆蓋線段樹

void

insertsegtree(segnode *tree, 

intlow, 

inthigh)  

}  // 從線段樹中刪除線段

void

deletesegtree(segnode *tree, 

intlow, 

inthigh)  

}  // 線段樹中是否包含線段(low,high)

bool

findsegtree(segnode *tree, 

intlow, 

inthigh)  

return

false

;  }  

#define left  true

#define right false

#define inf 10000

// 表示豎直方向的線段

struct

line  

};  

// 所有豎直方向的線段

line lines[inf];  

// 對橫向超元線段進行分組

intindex[inf];  

intncnt = 0;  

// 獲取key的位置

intgetindex(

intkey)  

// 獲取key的位置或比它小的最大數的位置

intgetlower(

intkey)  

// 獲取key的位置或比它大的最小數的位置

intgetupper(

intkey)  

intmain()  

// 待查詢的視窗區域

line search[2];  

cin >> x[0] >> y[0] >> x[1] >> y[1];  

search[0].x=x[0];         search[1].x=x[1];  

search[0].starty=search[1].starty=min(y[0],y[1]);  

search[0].endy=search[1].endy=max(y[0],y[1]);  

search[0].inout=left;     search[1].inout=right;  

// 對x座標進行排序o(nlogn)

sort(index, index+2*nrec);  

sort(lines, lines+2*nrec);  

// 排除index陣列中的重複資料o(n)

for(i=1; i<2*nrec; i++)  

if(index[i]!=index[i-1])  

index[ncnt++] = index[i-1];  

index[ncnt++] = index[2*nrec-1];  

// 建立線段樹

segnode *tree;  

buildsegtree(tree, index, 0, ncnt-1);  

// 單詞查詢的時間複雜度為o(nlogn)

bool

res;  

insertsegtree(tree, getindex(lines[0].starty), getindex(lines[0].endy));  

for(i=1; i<2*nrec; i++)  

else

if(search[1].x <= lines[i].x)  

break

;  }  

if(res) printf(

"yes\n"

);  

else

printf(

"no\n"

);  

return

0;  

}   更多0

程式設計之美2 19 區間重合判斷

題目 給定乙個源區間 x,y y x 和n個無序的目標區間 x1,y1 x2,y2 x3,y3 xn,yn 判斷源區間 x,y 是不是在目標區間內?例如,給定源區間 1,6 和一組無序的目標區間 2,3 1,1 3,9 即可認為區間 1,6 在區間 2,3 1,1 3,9 內,因為目標區間實際上是 ...

程式設計之美 2 19 區間重合判斷

題目大意 給定源區間 x,y x y 和 n個無序的目標區間 xi,yi 1 i n 判斷源區間是否在目標區間內。分析 書中介紹了兩種解法。第一種 將目標區間投影到源區間,看最終未被覆蓋的區間是否變為。這種方法的複雜度無疑是很高的。o n 2 另外,對於k組源區間查詢,其複雜度是單次的k倍。第二種 ...

程式設計之美 2 19 區間重合判斷

給定乙個源區間 x,y y x 和n個無序的目標區間 x1,y1 x2,y2 xn,yn 判斷源區間 x,y 是不是在目標區間內 eg,給定乙個源區間 1,6 和一組無序的目標區間 2,3 1,2 3,9 即可認為 1,6 在區間 2,3 1,2 3,9 內 因為目標區間合併之後,實質為 1,9 i...