BKG:某天晚上和dkw闲聊,然后随机到了一个题(ZOJ1015 Fishing Net)。
想了半天不会做。不久之后dkw说他看了题解……然后我们就找来了这个课件。。
感觉还是挺魔性的。
今天T3也是一个Chord Graph TAT.
行,现在开始抄课件.
图的定义
子图
图 G=(V,E), G'=(V',E'),V' \subseteq V , E' \subseteq E 为图 G 的子图。
诱导子图
G'=(V',E'),V' \subseteq V,E'=\{(u,v)|u,v \in V',(u,v) \in E \} 称为 G 的诱导子图。
团
图 G 的一个子图 G',满足 G' 为关于 V' 的完全图。
极大团
一个团是极大团,当它不是其他团的子集。
最大团
点数最多的团。记为 \omega (G)
最小染色
用最少的颜色给点染色使相邻点颜色不同。色数记为 \chi (G) .
最大独立集
一个点集的最大子集使得任意两个点不连通。记为 \alpha (G) .
最小团覆盖
可以覆盖所有的点的最小团数。团数记为 \kappa (G) .
定理
\omega (G) \leqslant \chi (G) .
\alpha (G) \leqslant \kappa (G) .
弦(Chord)
连接环中的不相邻两个点的边。
弦图
一个无向图,图中任意长度 \geqslant 3 的环都至少有一个弦。
定理
弦图的每一个诱导子图一定是弦图。
弦图的任一个诱导子图不同构于 C_n \; (n>3) . (?)
弦图判定
单纯点
一个点称为单纯点,当它和与它相连的所有点构成的诱导子图是一个团。
Lemma
任何一个弦图有至少一个单纯点,不是完全图的弦图至少有两个不相邻的单纯点。
完美消除序列
一个点组成的序列 v_1,v_2,v_3,\cdots ,v_n ,满足 v_i 在 \{ v_i,v_{i+1},\cdots,v_n \} 的诱导子图中是一个单纯点。
定理
一个无向图是一个弦图,当且仅当它有一个完美消除序列。
证明:略,详见课件qwq
Lexicographic BFS (LexBFS,字典序BFS)
实现困难又难记,我选择不写。
时间复杂度O(n+m) .
MCS (Maximum Cardinality Search,最大势算法)
这个算法要做的就是按照从 n 到 1 顺序依次给每个点标号。标号为 i 的点是完美消除序列中的第 i 个点。
设 l[i] 表示第 i 个点与多少个已经标号的点相邻,每次选择一个 l 最大的未标号点进行标号。
😕 这个代码挺好的,但是有一点问题就是如何维护largest label.
有一个做法就是维护一个链表,并维护最大值。这样每次更新 \mathrm{label} 都是 O(1) 左右的。
还要啰嗦一句的是,存在MCS和BFS都得不到的完美消除序列。(但是我不会找…… 🙁 )
相邻点判定完美消除序列(判定弦图)
从 1 \sim n 枚举序列中的每个点。
设 \{ v_{i+1},\cdots ,v_n \} 中所有与 v_i 相邻的点依次为 v_{j1},\cdots,v_{jk} 。
每次判断 v_{j1} 是否与 v_{j2},\cdots,v_{jk} 相邻即可。
时间复杂度 O(n+m) 。算法的正确性证明咕了,等我翻完论文看看有没有给出。
CODE
这份是 BZOJ1242 的代码,这玩意包括了求一个图的 PEO (Perfect Elimination Orderings) 和判定一张图是不是弦图 QAQ
(这段文字和这篇文章的首发差了半年的时间,233
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<iterator> #include<cstdlib> #include<queue> #include<vector> #include<map> #include<set> #define ll long long using namespace std; struct ed { int pre,to; }edge[1000010]; int at=1,ptr[1010]; int n,m,ans=1,G[1010][1010]; int peo[1010],id[1010],theta[1010]; vector<int> theta_list[1010]; template<typename int_t> void readx(int_t& x) { x=0; int_t k=1; char ch=0; while (ch<'0' || ch>'9') { ch=getchar(); if (ch=='-') k=-1; } while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); } x*=k; } void Is(int fx,int tx) { at++; edge[at].pre=ptr[fx]; edge[at].to=tx; ptr[fx]=at; at++; edge[at].pre=ptr[tx]; edge[at].to=fx; ptr[tx]=at; } int main() { readx(n); readx(m); int fx,tx; for (int i=1;i<=m;i++) { readx(fx); readx(tx); G[fx][tx]=G[tx][fx]=1; Is(fx,tx); } int maxtheta=0; for (int i=1;i<=n;i++) theta_list[0].push_back(i); for (int i=n;i;i--) { int now=0; while (1) { now=theta_list[maxtheta].back(); if (id[now]) theta_list[maxtheta].pop_back(); else break; while (theta_list[maxtheta].empty()) --maxtheta; } peo[i]=now; id[now]=i; for (int v=ptr[now];v;v=edge[v].pre) if (!id[edge[v].to]) { theta[edge[v].to]++; maxtheta=max(maxtheta,theta[edge[v].to]); theta_list[theta[edge[v].to]].push_back(edge[v].to); } } for (int i=n;i;i--) { int u=peo[i],J=0; for (int v=ptr[u];v;v=edge[v].pre) if (id[edge[v].to]>id[u]) if ((!J) || id[J]>id[edge[v].to]) J=edge[v].to; for (int v=ptr[u];v;v=edge[v].pre) if (id[edge[v].to]>id[u]) if (edge[v].to!=J && (!G[edge[v].to][J])) { ans=0; break; } } printf(ans?"Perfect\n":"Imperfect\n"); } |
弦图相关
寻找极大团
Lemma
设第 i 个点在弦图的完美消除序列的第 p(i) 个。
N(v)= \{ w | w \text{与} v \text{相邻且} p(w)>p(v) \} ,那么弦图的极大团一定是 v \cup N(v) 的形式。
推论
弦图最多有 n 个极大团。
我们只需要判定每个 v \cup N(v) 是否为极大团。
设 A = v \cup N(v) , 若存在 B = w \cup N(w) 使得 A \subseteq B 则 A 不是极大团。
首先我们可以得到 p(w)<p(v) 。
设 \mathrm{next} (v) 表示 N(v) 中最前的点, w* 表示在所有满足 A \subseteq B 的 w 中最后的一个点。
可知 \mathrm{next} (w*) = v 。若不是,则 \mathrm{next} (w*) 也是一个满足上述条件的点,得证。
那么, v \cup N(v) \subseteq w \cup N(w) 当且仅当 | N(v) | +1 \leqslant | N(w) | 。
我们只需要判定是否存在一个 w ,满足 \mathrm{next} (w) = v 且 | N(v) | +1 \leqslant | N(w) | 即可。
时间复杂度 O(n+m) 。
<<此处本应有代码>>
弦图点染色
行……我们终于来到了这个题……
HNOI2008 神奇的国度。
用最少的颜色给每个点染色,使得相邻的点染色不同。
有一个神奇的做法:
求出完美消除序列,从后向前给每个点染上可以染的最小色。
团数=色数。证明:比较简单,咕了,看课件吧
O(n+m)
弦图最大独立集,最小团覆盖
最大独立集:完美消除序列从前往后能选就选。
最小团覆盖:最大独立集的每个点都与它的邻点组成一个团,以此求出最小团覆盖。
\alpha (G) = \kappa (G) 。
区间图
定义
在序列上给定一些区间,定义一个相交图为:
- 每个顶点表示一个区间
- 两点之间有边,当且仅当对应代表的区间的交集非空。
如果一个图是若干区间的相交图,则它是区间图。
定理
区间图一定是弦图。
证明略,详见课件。
区间图完美消除序列
将所有的区间按照右端点从小到大排序。
没了。。。证明depends on我能不能找到了
区间图最大独立集
问题:给定 n 个区间,求一个选择最多区间的方案,使得所有区间的交集为空。
Sol:最裸的题,最大独立集。完美消除序列上的判定可以做到 O(n\log _2 n) (线段树或堆),非常优秀。
区间图最小染色
有 n 个高度均为 1 的积木,第 i 个位于 [L_i,R_i] 的位置 (也就是起点在 L_i ,宽 R_i-L_i )。
求一个积木下落顺序,使得最后积木总高度尽可能小。
就是求一个最小染色,方案则是按照颜色编号从小到大掉落。
一个很意识流的解释就是尽量让不交的区间落在一层上。
更多实现上的细节:我们可以倒过来排序,然后依次处理。也是 O(n \log _2 n) 的。
判定区间图
- 判定是否为弦图。
- 找出所有的极大团。
- 构建一个 顶点-团矩阵 A ,使得 A 的每一行代表 G 的一个顶点,每一列代表 G 的极大团。满足 A_{ij}=\begin{cases} 1 \; \mathrm{if} \; v_i \in C_j \\ 0 \; \mathrm{otherwise} \end{cases}
- 判断是否存在一个重排方式,即任意交换 A 的各列,使得每行的所有 1 都是连续的。如果这种排列存在,就称这个矩阵具有连续 1 性质。
- 可以用PQTree来实现(这就是作死)
- 另外一种判定方法
- 《A new Test for Interval Graphs》
Tree Decomposition
一个无向图 G=(V,E) 的 树的分解(Tree Decomposition) 定义为 (X,T) ,\; X= \{ X_1,X_2, \cdots ,X_m \} ,其中 X_i 为 V 的一个子集, T 是一棵树,点集为 X 。
一些性质
X_1 \cup X_2 \cup \cdots \cup X_m = V
对于 G 中任意一条边 (u,v) \;,\; \exists X_i 使得 u,v \in X_i 。
对于每个点 v,P(v)= \{ X_i | v \in X_i \} ,则 T 中 P(v) 的诱导子图是联通的。
所以这玩意到底有啥用啊 🙁
Clique Tree
clique tree是一种tree decomposition.
一个无向图 G 为弦图当且仅当存在一个clique tree.
一个无向图为区间图当且仅当存在一个链形态的clique tree
所以这玩意到底又有啥用啊 🙁
构建弦图Clique Tree
感觉这玩意没用。我Bing了一下Clique Tree看到的全是概率学的玄学……
愿意学的看课件吧。
Orz
楼上是假的 被**了