Sicily 連通性問題 演算法逐層優化

2021-07-24 00:28:00 字數 3115 閱讀 9115

description:

關係r具有對稱性和傳遞性。數對p q表示prq,p和q是0或自然數,p不等於q。

要求寫乙個程式將數對序列進行過濾,如果乙個數對可以通過前面數對的傳遞性得到,則將其濾去。例如:

輸入 輸出 連通性

3 4— 3 4

4 9— 4 9

8 0— 8 0

2 3— 2 3

5 6— 5 6

2 9— xx— 2-3-4-9

5 9— 5 9

7 3— 7 3

4 8— 4 8

5 6— xx— 5-6

0 2— xx— 0-8-4-3-2

6 1— 6 1

其中數對2 9和0 2可由之前數對的連通關係得到,故不做輸出。

input

輸入共有m行(0<=m<=1000000),每行乙個數對,數對的數字之間以1個空格分隔;數對的數字為0或n=100000以內的自然數。

output

輸出包含過濾之後的數對序列。每行輸出乙個數對,數對的數字之間以1個空格分隔。

sample input

3 4

4 9

8 0

2 3

5 6

2 9

5 9

7 3

4 8

5 6

0 2

6 1

sample output

3 4

4 9

8 0

2 3

5 6

5 9

7 3

4 8

6 1

看完題目,第一反應就是動態構造圖,然後每次輸入時進行連通性檢查。但是仔細一看,發現根本行不通。

如題目所示,節點數可能達到100000,構造乙個鄰接矩陣即使是bool型別也顯然超出記憶體限制,同時輸入資料可能達到1000000,每一次都進行bfs或dfs連通性檢測顯然會嚴重超時。

那麼只有走其他方法!

對於連通性檢測,如已知圖2-3-4-5,顯然2-3,2-4,2-5,3-4,3-5,4-5都是需要過濾的,不難發現:2是3,4,5的共同祖先,或者反過來,5是2,3,4的共同祖先。由此可以聯想到union-find,對結點進行分組。

我採用的第一種方法**如下:

# include 

# define max 100001

using

namespace

std;

int data[max];

int main(void)

int point1, point2;

while(cin >> point1 >> point2) }}

}return

0;}

起初每個節點都屬於自己的組,我就暫且將它們各自的編號定義為它們的index。

當要查詢的兩個index在陣列中的值不同時,說明它們不屬於同乙個組,應當連通;否則,說明它們已經連通,需要過濾掉。

但有一點要注意,在連通時,應當把兩個組內所有成員都進行連通,但是我們又不知道哪些需要連通,只能把陣列遍歷一遍進行連通。

但是提交後發現**超時了!

接下來就是改進我的**了。

很顯然就是在連通時遍歷陣列耗時太長了,每一次連通都把100001個資料遍歷一次,實在是資源浪費,因為有時並沒有那麼多結點。

所以我改進了**,如下:

# include 

# define max 100001

using

namespace

std;

int data[max];

int _max = 0;

int main(void)

int point1, point2;

while(cin >> point1 >> point2) }}

}return

0;}

我用_max變數儲存最大結點的值,這樣一來就不用將所有資料遍歷。

但是一提交,還是超時了!我估計測試資料裡可能一早就用到了乙個很大很大的結點。所以我改進後的**還是廢柴。

那麼,還是需要改進!!!

問題是:怎麼才能避免遍歷陣列?因為不知道哪些結點需要進行連通,才導致我們需要遍歷整個陣列。那麼我們怎樣才能找到這些結點而不需要遍歷陣列呢?

肯定要用到某種資料結構。鍊錶?集合?更深一層想,查詢最高效的就是樹了。

使用樹,我便能層層回溯,找到根結點,也就是它最終所屬的組,這樣我就可以避免遍歷了!

於是我進一步改進了我的**:

# include 

# define max 100001

using

namespace

std;

int data[max];

int _max = 0;

int find(int num)

int main(void)

int point1, point2;

while(cin >> point1 >> point2)

}return

0;}

本想著這次肯定萬無一失能夠通過,還是太嫩了!依然超時!

為什麼會這樣?說明樹太深了,導致每次查詢根結點的時候耗費的資源太多了!我們必須在查詢的過程中將樹簡化。

於是我就修改了find函式,**如下:

# include 

# define max 100001

using

namespace

std;

int data[max];

int _max = 0;

int find(int num)

int main(void)

int point1, point2;

while(cin >> point1 >> point2)

}return

0;}

然後,終於過了,哈哈哈~真是有趣的一道題!

連通性問題

1 伺服器可以ping通客戶端,說明伺服器和客戶端之間的鏈路是通的。客戶端不能ping通伺服器,很可能是防火牆的原因,包括伺服器本身自帶的防火牆和伺服器與交換機之間的cisco asa 5505防火牆。防火牆的訪問規則中清除禁止ping入之類的規則,或者清除拒絕接收icmp包的規則。2 ping不通...

動態連通性問題

首先定義演算法的api 方法作用 uf int n 初始化觸點及其他資料 int find int p 返回p所在連通分量的識別符號 int union int p,int q 在p和q之間新增一條線 int count 返回連通分量的數量 boolean connected int p,int q...

SOJ 連通性問題

description 關係r具有對稱性和傳遞性。數對p q表示prq,p和q是0或自然數,p不等於q。要求寫乙個程式將數對序列進行過濾,如果乙個數對可以通過前面數對的傳遞性得到,則將其濾去。例如 輸入 輸出 連通性 3 4 3 4 4 9 4 9 8 0 8 0 2 3 2 3 5 6 5 6 2...