一些定义
最大团点数最多的团, 记为团数 ω ( G ) \omega(G) ω ( G )
弦(chord) :连接环中不相邻的两个点的边。
弦图(chordal graph) :一个无向图称为弦图当图中任意长度大于3的环都至少有一个弦。
弦图的每一个诱导子图一定是弦图。
单纯点(simplicial vertex) :设 N ( v ) N(v) N ( v ) 表示与点 v v v 相邻的点集。一个点称为单纯点当 { v } + N ( v ) \{v\} + N(v) { v } + N ( v ) 的诱导子图为一个团。
引理:任何一个弦图都至少有一个单纯点,不是完全图的弦图至少有两个不相邻的单纯点。
完美消除序列
定义
定义:一个点的序列(每个点出现且恰好出现一次) v 1 , v 2 , ⋯ , v n v_1, v_2,\cdots, v_n v 1 , v 2 , ⋯ , v n 满足 v i v_i v i 在{ v i , v i + 1 , ⋯ , v n } \{v_i, v_{i+1},\cdots,v_n\} { v i , v i + 1 , ⋯ , v n } 的诱导子图中为一个单纯点。
定理
一个无向图是弦图当且仅当它有一个完美消除序列。
最大势算法 Maximum Cardinality Search
从 n n n 到 1 1 1 的顺序依次给点标号 (标号为 i i i 的点出现在完美消除序列的第 i i i 个)。
设 label i \text{label}_i label i 表示第 i i i 个点与多少个已标号的点相邻,每次选择 label i \text{label}_i label i 最大的未标号的点进行标号。
不难发现 label i \text{label}_i label i 的值是单调的,且权值在 [ 0 , n ] [0,n] [ 0 , n ] 之间,所以只要对每一个权值开一个链表,再维护一个指针即可做到 O ( n + m ) O(n+m) O ( n + m ) 。
弦图的点染色问题
用最少的颜色给每个点染色使得相邻的点染的颜色不同。
HNOI2008 神奇的国度
团数 ω ( G ) \omega(G) ω ( G ) = 色数 χ ( G ) \chi(G) χ ( G )
完美消除序列从后往前依次给每个点染色,给每个点染上可以染的最小的颜色。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <iostream> #include <algorithm> #include <vector> using namespace std;int main () { cin.tie (nullptr )->sync_with_stdio (0 ); int n , m; cin >> n >> m; vector<vector<int >> G (n + 1 , vector<int >()); for (int i = 1 ; i <= m ; i++) { int u , v; cin >> u >> v; G[u].push_back (v); G[v].push_back (u); } vector<vector<int >> p (n + 1 , vector<int >()); vector<int > vis (n + 1 ) , label (n + 1 ) ; for (int i = 1 ; i <= n ; i++) { p[0 ].push_back (i); } int cur = 0 ; for (int i = n ; i >= 1 ; i--) { int flag = true , u = 0 ; while (flag) { for (int j = p[cur].size () - 1 ; j >= 0 ; j--) { int v = p[cur][j]; if (!vis[v]) { vis[v] = 1 , flag = 0 ; u = v; break ; } p[cur].pop_back (); } if (flag) --cur; } for (int v : G[u]) { if (vis[v]) continue ; p[++label[v]].push_back (v); cur = max (cur , label[v]); } } cout << *max_element (label.begin () , label.end ()) + 1 << endl; return 0 ; }
最大独立集
完美消除序列 从前往后能选就选 , 最大独立集记为 α ( G ) \alpha(G) α ( G )
最小团覆盖
设最大独立集为 { p 1 , p 2 , ⋯ , p t } \{p_1 , p_2 , \cdots , p_t\} { p 1 , p 2 , ⋯ , p t } ,则 { p 1 ∪ N ( p 1 ) , ⋯ , p t ∪ N ( p t ) } \{p_1 \cup N(p_1), \cdots, p_t \cup N(p_t)\} { p 1 ∪ N ( p 1 ) , ⋯ , p t ∪ N ( p t )} 为最小团覆盖。 记为 κ ( G ) \kappa(G) κ ( G )
最大独立集数 = 最小团覆盖数
完美图与伴完美图
完美图 (Perfect Graph) 的概念
一个图 G G G 称为完美图若它的每一个诱导子图都满足 ω ( G ) = χ ( G ) \omega(G)=\chi(G) ω ( G ) = χ ( G )
伴完美图 (Co-perfect Graph) 的概念
一个图 G G G 称为伴完美图若它的每一个诱导子图都满足 α ( G ) = κ ( G ) \alpha(G) = \kappa(G) α ( G ) = κ ( G )
完美图 = 伴完美图 , 弦图属于完美图。
区间图
区间图 (Interval Graph) 定义
给定一些区间,定义一个相交图为每个顶点表示一个区间,两个点有边当且仅当两个区间的交集非空。
一个图为区间图当它是若干个区间的相交图。
区间图一定是弦图。
区间图完美序列求法
给定 n n n 个区间,所对应的区间图为 G G G
G G G 的一个完美消除序列:将所有的区间按照右端点从小到大排序。
例题1
给定 n n n 个区间,要求选择最多的区间使得区间不互相重叠
即求区间图的最大独立集。
将所有的区间按照右端点从小 到大 排序,依次处理每个区间,如果与已选区间没有重叠则选择该区间。
时间复杂度:O ( n log n ) O(n\log n) O ( n log n )
例题2
有 n n n 个积木,高度均为 1 1 1 ,第 i i i 个积木的宽度范围为 [ L i , R i ] [L_i, R_i] [ L i , R i ] ,选择一个积木的下落顺序使得最后积木总高度尽可能小。
即求区间图的最小染色。积木下落顺序:按照颜色标号从小到大落下。
将所有的区间按照右端点从大 到小 排序,依次处理每个区间,选择一个可以染的最小的颜色染色。
时间复杂度:O ( n log n ) O(n\log n) O ( n log n )