最大團問題

名詞解釋

圖Graph

1. 圖由點和邊所組成

點:1, 2, 3, 4, 5

邊:(1, 4)、(3, 5)、...

 

2. 若兩個點由一條邊所連接,則稱此兩個點「相鄰」

ex:

3 與 5 相鄰

2 與 4 相鄰

3. 我們將點 v 的鄰居的集合

記為:\(N(v)\)

度數Degree

一個點所連出的邊的數量

ex:

deg(1) = 3

deg(5) = 2

deg(2) = 4

子圖Subgraph

給定一張圖G

取這張圖中的幾個點

並保留點之間的邊

所形成的圖稱為G的子圖

二分圖

一張圖G可以將點分成兩部分

每部分之間互相不相鄰

p-分圖

一張圖G可以將點分成 p 部分

每部分之間互相不相鄰

(圖by wiki)

完全p-分圖

一張圖G可以將點分成 p 部分

每部分之間互相不相鄰

並且不同部分之間兩兩相鄰

(圖by wiki)

完全圖

Complete Graph

完全圖

給定一張圖

若這張圖中任兩點都相鄰

則稱為完全圖

這是完全圖嗎?

完全圖必須是「整張圖」的任兩點都相鄰

完全圖的性質

  1. 任兩點皆相鄰
  2. 每個點度數都一樣
  3. 總共有 \(\frac{V\times(V+1)}{2}\) 條邊
  4. 任兩點的距離為 \( 1 \)
  5. 任兩點的最遠距離為 \(V - 1\)
  6. 有漢米爾頓迴圈   

...... etc.

完全圖的性質

完全圖的邊的數量是 \(O(V^2)\)

反過來說

完全圖的點的數量是 \(O(\sqrt E)\)

有一些關於完全圖的題目

可以藉由「完全圖的點與邊的數量很懸殊」

這個性質來進行剪枝

團Clique

給定一張圖G

若其一個子圖G'是完全圖

則稱G'是G的一個團

 

ex:

{1, 2, 3}是團

{1, 2, 3, 4}是團

極大團 Maximal Clique

對於一個團

如果無法再加入任何一個點

則稱為極大團

 

ex:

{1, 2, 3}並非極大團

{3, 4, 5} 是極大團

最大團 Maximum Clique

點數最多的團

稱作最大團

 

ex:

{1, 2, 3, 4}是最大團

給你一個 \(N\) 個點的完全圖

請問最大團的大小是多少?

給你一個 \(N\) 個點的樹

請問最大團的大小為多少?

練習題

一張圖可能有兩個相異的最大團嗎?

一張 p-分圖有多少個不同的極大團呢?

練習題

\(\prod\limits_{i=1}^p |V_i|\)

每一個部分都可以任意選一個點

尋找最大團

尋找最大團

給定一張 \(N\) 個點 \(M\) 條邊的圖

請問這張圖的最大團是多少?

這是NP-Complete問題QQ

尋找最大團

枚舉所有可能性

( 1 )
( 2 )
( 3 )
( 4 )

( 1, 2 )
( 1, 3 )
( 1, 4 )
( 2, 3 )
( 2, 4 )
( 3, 4 )

( 1, 2, 3 )
( 1, 2, 4 )
( 1, 3, 4 )
( 2, 3, 4 )
( 1, 2, 3, 4 )

只有( 1, 2, 3 )是團

尋找最大團

枚舉所有可能性

共有 \(O(2^N)\) 種狀態

每種狀態要 \(O(N^2)\) 去檢查

複雜度: \(O(N^2\times2^N)\) 

for (int i = 0; i < pow(2, n) - 1; i ++) {
    vector<int> v;
    for (int j = 0; j < n; j ++)
        if ((i >> j) & 1)
            v.push_back(j);
            
    bool ok = 1;
    for (int a : v) {
    	for (int b : v) {
            if (a == b) continue;
            if (a與b不相鄰) ok = 0;
        }
    }
    if (ok) ans = max(ans, v.size());
}

尋找最大團

枚舉所有可能性

共有 \(O(2^N)\) 種狀態

每個狀態要 \(O(N)\) 去檢查

複雜度: \(O(N\times2^N)\) 

// s 是目前的團
void Dfs(int i) {
    if (i > n) {
        ans = max(ans, s.size());
        return;
    }
    bool ok = 1;
    for (int a : s)
        if (i和a不相鄰)
            ok = 0;
    if (ok) {
        s.insert(i);
        Dfs(i + 1);
        s.erase(i);
    }
    Dfs(i + 1);
}

尋找最大團

剪枝:代價函數

共有 \(O(2^N)\) 種狀態

每個狀態要 \(O(N)\) 去檢查

複雜度: \(O(N\times2^N)\) 

// s 是目前的團
void Dfs(int i) {
    if (s.size() + (n - i) <= ans)
        return;
    if (i > n) {
        ans = max(ans, s.size());
        return;
    }
    bool ok = 1;
    for (int a : s)
        if (i和a不相鄰)
            ok = 0;
    if (ok) {
        s.insert(i);
        Dfs(i + 1);
        s.erase(i);
    }
    Dfs(i + 1);
}

找出極大團

找出極大團

一張圖最多有多少個不同的極大團呢?

給定一張 \(N\) 個點 \(M\) 條邊的圖

請求出「所有」這張圖的極大團

(極大團代表無法再加入任何額外的點)

找出極大團

考慮兩個沒有共同鄰居的兩個點:x, y

那麼 x 肯定不可能同時與 y 在同個極大團中

假設包含 x 的極大團的數量為: \(C_x\)

  包含 y 的極大團的數量為: \(C_y\)

且不失一般性的,假設 \(C_x \leq C_y\)

那麼若是把 x 從圖上拔掉

並且加入一個點 x' 並且 x' 與 y 的所有鄰居都相鄰

那整張圖的極大團數量會如何變化呢?

找出極大團

x = 7

y = 4

x' = 8

找出極大團

  1. 會多出 \(C_y\) 個極大團
  2. 「原本包含 x 的極大團的子圖」中,變成了真的極大團

 

變化量至少為: \(-C_x + C_y + 0 \geq 0\)

因此經過這樣的操作,極大團數量只有可能變多

那能夠一直執行操作直到甚麼時候呢?

找出極大團

最後會變成一張完全p-分圖

(此分析by tmt's blog)

完全p-分圖上的極大團數量為:

\(\prod\limits_{i=1}^{p}\lfloor V_i \rfloor\)

假設 \(\sum\limits_{i=1}^p V_i = N\) 根據分析可得

上式的最大值出現在: \(O(3^\frac{N}{3})\)

極大團的數量

一張圖中最多有 \(O(3^\frac{N}{3})\) 個極大團

因此這個問題不可能以多項式時間解決

給定一張 \(N\) 個點 \(M\) 條邊的圖

請求出所有這張圖的極大團

(極大團代表無法再加入任何額外的點)

可行嗎?

枚舉所有可能性

for (int i = 0; i < pow(2, n) - 1; i ++) {
    vector<int> v;
    for (int j = 0; j < n; j ++)
        if ((i >> j) & 1)
            v.push_back(j);
            
    bool ok = 1;
    for (int a : v) {
    	for (int b : v) {
            if (a == b) continue;
            if (a與b不相鄰) ok = 0;
        }
    }
    if (ok) ans += 1;
}

極大團:有可能可以再加入其他點

可行嗎?

枚舉所有可能性

for (int i = 0; i < pow(2, n) - 1; i ++) {
    if (i是已經做過的點的子集的話) continue;
    vector<int> v;
    for (int j = 0; j < n; j ++)
        if ((i >> j) & 1)
            v.push_back(j);
            
    bool ok = 1;
    for (int a : v) {
    	for (int b : v) {
            if (a == b) continue;
            if (a與b不相鄰) ok = 0;
        }
    }
    if (ok) ans += 1;
}

複雜度:\(O(N^2\times 2^N)\)

Bron–Kerbosch algorithm

維護三個集合:R、P、X

對於我們目前所搜索到的極大團的子圖

必須要包含:

R中所有的點

P中部分的點

不包含X中任何點

 

演算法開始時, \(R=\{ \}, P=\{V\}, X=\{ \}\)

當 \(P = X = \{\}\) 時,R中所有點構成一個極大團

Bron–Kerbosch algorithm

algorithm BronKerbosch1(R, P, X) is
    if P and X are both empty then
        report R as a maximal clique
    for each vertex v in P do
        BronKerbosch1(R ⋃ {v}, P ⋂ N(v), X ⋂ N(v))
        P := P \ {v}
        X := X ⋃ {v}

R:目前構成團的那些點

P:可能可以加入團的那些點(候選的點)

X:已經搜索過的點,而不能再被加入

by wiki

Bron–Kerbosch algorithm

algorithm BronKerbosch1(R, P, X) is
    if P and X are both empty then
        report R as a maximal clique
    for each vertex v in P do
        BronKerbosch1(R ⋃ {v}, P ⋂ N(v), X ⋂ N(v))
        P := P \ {v}
        X := X ⋃ {v}

by wiki

P為空時,若X為空,則R為極大團

P為空時,若X非空,代表R可擴充

但X中的點都是做過的

Bron–Kerbosch algorithm

by wiki

BronKerbosch2(Ø, {1,2,3,4,5,6}, Ø)
    BronKerbosch2({2}, {1,3,5}, Ø)
        BronKerbosch2({2,3}, Ø, Ø): output {2, 3}
        BronKerbosch2({2,5}, {1}, Ø)
            BronKerbosch2({1,2,5}, Ø, Ø): output {1,2,5}
    BronKerbosch2({4}, {3,5,6}, Ø)
        BronKerbosch2({3,4}, Ø, Ø): output {3,4}
        BronKerbosch2({4,5}, Ø, Ø): output {4,5}
        BronKerbosch2({4,6}, Ø, Ø): output {4,6}
    BronKerbosch2({6}, Ø, {4}): no output

Bron–Kerbosch algorithm

優化 by wiki

algorithm BronKerbosch2(R, P, X) is
    if P and X are both empty then
        report R as a maximal clique
    choose a pivot vertex u in P ⋃ X
    for each vertex v in P \ N(u) do
        BronKerbosch2(R ⋃ {v}, P ⋂ N(v), X ⋂ N(v))
        P := P \ {v}
        X := X ⋃ {v}

對於一個極大團

要嘛包含 u (而 u 做過了)

要嘛至少包含一個不是 u 的鄰居的點

因此 u 的鄰居就不用搜了

Bron–Kerbosch algorithm

複雜度 by tmt's blog

為了盡可能優化

所以選的點 u 的 \(|N(u)|\) 要盡可能大

這件事情可以在 \(O(|P|^2)\) 內辦到

T(|P|) = \max\limits_{N(u)} \{(|P|-N(u))\times T(N(u))\} + O(N^2)

根據論文可知: \(T(N) = O(3^{\frac{N}{3}})\) = O(1.4422^N)

struct Maximum_Clique{
    typedef bitset<MAXN> bst;
    bst N[MAXN],empty;
    int p[MAXN],n,ans;
    void BronKerbosch2(bst R,bst P,bst X){
    	if(P==empty&&X==empty)
    	    return ans=max(ans,(int)R.count()),void();
    	bst tmp=P|X;
    	int u;
    	if((R|P|X).count()<=ans) return;
    	for(int uu=0;uu<n;++uu){
    	    u=p[uu];
    	    if(tmp[u]==1) break;
    	}
        //if (double(clock())/CLOCKS_PER_SEC > .999) return;
        bst now2=P&~N[u];
        for(int vv=0;vv<n;++vv){
            int v=p[vv];
            if(now2[v]==1){
                R[v]=1;
                BronKerbosch2(R,P&N[v],X&N[v]);
                R[v]=0,P[v]=0,X[v]=1;
            }
        }
    }
    void init(int _n){n=_n;
        for(int i=0;i<n;++i) N[i].reset();
    }
    void add_edge(int u,int v){N[u][v]=N[v][u]=1;}
    int solve(){//remember srand
        bst R,P,X;
        ans=0,P.flip();
        for(int i=0;i<n;++i) p[i]=i;
        random_shuffle(p,p+n),BronKerbosch2(R,P,X);
        return ans;
    }
};

pivot u的選擇

為了方便可以

直接random

 

(by BBQ's codebook)

Bron–Kerbosch algorithm

優化

還有一個根據The degeneracy of a graph

來優化的方法,但在此先跳過

有興趣的同學可以先自行研究看看

練習題

by tmt's blog

給定一張有 \(N\) 個點的圖G(以補圖的方式給出)

已知在G上有一個極大團的大小為\(\frac{2N}{3}\)

請設計一個演算法找出在G上一個大小至少為 \(\frac{N}{3}\)的團

練習題

  1. Zerojudge a858
  2. Codeforces D. Graph Subset Problem
  3. TIOJ在做投影片的時候掛掉了QQ

Zerojudge a858

給定 \(N\) 個點的完全圖

每條邊要嘛是紅色、要嘛是黑色

求這張圖總共有多少個同色的三角形

\(\binom{N}{3}\) 減掉非同色的三角形

D. Graph Subset Problem

給定一張 \(n\) 個點 \(m\) 條邊的圖和常數 \(k\)

如果存在一個子圖中,每個點的 \(deg\) 都大於 \(k\)

請輸出此子圖

若存在一個點數為 \(k\) 的團,則輸出此團

(\(n, m, k \leq 10^5\))

D. Graph Subset Problem

對於第一個小題

任何 \(deg\) 少於等於 \(k\) 的點都是沒用的

=>

將那些點一個一個拔掉,直到整張圖剩下 \(deg\) 大於 \(k\) 的點

或是整張圖是空的

D. Graph Subset Problem

對於第二小題

\(deg\) 小於 \(k-1\) 的點都是沒用的

=>

將那些點拔掉

若是圖是空的則無解

D. Graph Subset Problem

若圖非空

如果此時每個點的 \(deg\) 都大於 \(k - 1\) 

則代表第一小題有解

=>

至少存在一個點的 \(deg = k - 1\)

D. Graph Subset Problem

假設那個點為 \(v\)

減查 \(v \cup N(v)\)是不是團

是=>找到

否=>拔掉這個點,繼續檢查剩下的圖

D. Graph Subset Problem

\(\sqrt{2m} < k\) 時,肯定無解

=>

\( k = O(\sqrt m\)

檢查完全圖的複雜度: \(O(k^2)\)

只需要檢查 \(O(\frac{m}{k})\) 個點 (why?)

複雜度為: \(O(mk) \leq O(m^\frac{3}{2})\)

最大團問題

By polarischiba

最大團問題

清大程式設計競技社 進階班課程

  • 269