演算法 線段樹 活動排期衝突問題

2022-03-31 05:07:43 字數 3855 閱讀 9030

今天偶然遇到了乙個有點意思的問題,將它轉化成了題目,有點令人懷念:

有一張活動排期表,表上有n組活動的排期。其中,每組活動都會開啟若干次,每個活動都有乙個唯一id和乙個開啟時間a,關閉時間b。同組活動不能在相同時間內開啟兩個及以上。如果同組活動同時開啟,則會產生衝突,活動開啟失敗。問:當前活動表內是否存在衝突?如果存在,是哪幾個衝突?(如果活動表中id為x的活動和id為y的活動衝突,且xy>z時,x與z衝突,y與z衝突,且x和y不衝突,則只輸出一次「error: z」。而如果x與y衝突,x與z也衝突,則y與z都需要輸出,輸出:

「error: y」

「error: z」

輸入樣例:

1 1 1 10

2 2 1 10

3 1 12 15

4 1 5 11

輸出樣例:

failed

error: 4

看到這個題目,很容易想到,首先將這些輸入資料按照活動組號分組,比如輸入樣例1,3,4行為一組,第2行為一組。

然後在組內進行兩兩比較,第1行和第3行比較,因為1-10和12-15沒有重合,所以第1行和第3行不衝突。第1行和第4行比較,因為5>=1且5<=10,所以1-10和5-11有重合,這兩行衝突了。然後第3行和第4行比較,這兩行沒衝突。

這種方法花費的時間與輸入樣例中活動的組數和每組活動的行數有關,為∑((ai)^2)/2。i為每組資料的組號,ai為每組資料報含的行數。估算時間複雜度為o(n^2),n為行數。

由於「ps」裡的內容,可以使用一種優化——當前資料和前面的資料產生衝突時,記錄error然後直接返回。比如第4行資料和第1行資料比較後,不再和第3行資料比較。

這是我想起來的第一種演算法。這種演算法的優點是簡單明瞭,乙個乙個比較就好。缺點是當每組資料規模巨大時,消耗的時間成平方增長。

我好不容易遇到乙個有點意思的問題,怎麼能這樣放棄?於是我稍微思考了一會兒。想出了乙個新辦法:

之後只針對每組資料組內的處理進行描述,因為組與組之間沒有關聯,不需要額外處理。

我們設定乙個bool型陣列,初始全部置為0。每取一行資料,就以這組資料開始時間到結束時間之間的所有數字為下標,遍歷陣列內這些下標的值,如果存在乙個值為1,則記錄這行資料為error,否則將陣列內這些下標的值置為1。

第一組資料,初始有乙個陣列flag=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]。

讀入第1行後,置為flag=[1,1,1,1,1,1,1,1,1,1,0,0,0,0,0]。

讀入第3行後,置為flag=[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1]。

讀入第4行時,因為5-11中,flag[5-10]都已經為1了,所以產生衝突。

使用這種方法,處理每組資料花費的時間為組內每行資料的(結束時間-開始時間+1)之和,所有組的時間為∑(bi-ai+1)。估算時間複雜度為o(n*(b-a)),n為行數。

只需要(b-a)

1

#!/usr/bin/python2#

-*- encoding:utf8 -*-

3import

sys, os, io

4import

string

5import

commands

6import

time, datetime

78 actarr ={}

9 errarr ={}

1011

defcheckactivity():

12 file = open('

activity.txt')

1314 errcnt =0

15 linenum =0

16for fileline in

file:

1718

19 linenum += 1

20if (linenum <= 3):

21continue

2223 id = int(fileline.strip('

\n\r

').split('\t'

)[0])

24 enable = int(fileline.strip('

\n\r

').split('

\t')[2])

25 group = int(fileline.strip('

\n\r

').split('

\t')[3])

26 starttime = fileline.strip('

\n\r

').split('

\t')[4]

27 endtime = fileline.strip('

\n\r

').split('

\t')[5]

2829 timearray = time.strptime(fileline.strip('

\n\r

').split('

\t')[4], "

%y-%m-%d-%h:%m:%s")

30 starttime =int(time.mktime(timearray))

31 timearray = time.strptime(fileline.strip('

\n\r

').split('

\t')[5], "

%y-%m-%d-%h:%m:%s")

32 endtime =int(time.mktime(timearray))

3334

#print enable,group,starttime,endtime

35if(enable ==0):

36continue

3738 tmparr =[id, enable, group, starttime, endtime]

3940 actarrtmp =

41if(group in

actarr):

42for arrline in

actarr[group]:

4344

45if( (arrline[3] <= starttime and arrline[4] >= starttime) or ( arrline[3] <= endtime and arrline[4] >=endtime ) ):

46 errarr[errcnt] = [0, arrline[0], enable, group, arrline[3], arrline[4]]

47 errcnt = errcnt+1

48 errarr[errcnt] = [1, id, enable, group, starttime, endtime]

49 errcnt = errcnt+1

50break

51 actarrtmp =actarr[group]

5253

54 actarr[group] =actarrtmp55#

print actarr[group]

5657

for errindex in

errarr:

58print

'error id:

',errarr[errindex][1]

5960

if(errcnt ==0):

61print

"success!"62

63file.close()

6465 checkactivity()

演算法 線段樹

幾次的省賽,成績都不是很理想。不過這幾次省賽的給我們留下了很多寶貴的經驗 首先發現的是線段樹,每考必有 今天我們學習的就是線段樹 線段樹的功能是 1 對一段數字進行累加。2 對數字進行搜尋。3 將包含在區間int的元素x插入到樹t中。4 從線段樹中刪除元素x。5 對線段樹上的資料進行更新。今天,我們...

演算法 線段樹

線段樹的根節點是整段區間,其它結點是由區間不斷二分得到的子區間,其中葉子結點是區間的每個單獨的元素。這裡使用結構體存線段樹。struct tree tree 4 maxn 2 注意陣列大小至少要開到區間長度的四倍大這裡預設我們要求的是區間和,故結點值均為區間和。可以視情況改變結點值的含義。void ...

RMQ問題 線段樹演算法,ST演算法優化

對於長度為n的數列a,回答若干詢問rmq a,i,j i,j n 返回數列a中下標在 i,j 裡的最小 大 值,也就是說,rmq問題是指求區間最值的問題 主要方法及複雜度 處理複雜度和查詢複雜度 如下 1.樸素 即搜尋 o n o n 2.線段樹 segment tree o n o qlogn 3...