弦图
弦图是一种特殊的图,很多在一般图上的 NP-Hard 问题在弦图上都有优秀的线性时间复杂度算法。
一些定义与性质¶
子图:点集和边集均为原图点集和边集子集的图。
导出子图(诱导子图):点集为原图点集子集,边集为所有满足 两个端点均在选定点集中 的图。
团:完全子图。
极大团:不是其他团子图的图。
最大团:点数最大的团。
团数:最大团的点数,记为
最小染色:用最少的颜色给点染色使得所有边连接的两点颜色不同。
色数:最小染色的颜色数,记为
最大独立集:最大的点集使得点集中任意两点都没有边直接相连。该集合的大小记为
最小团覆盖:用最少的团覆盖所有的点。使用团的数量记为
弦:连接环中不相邻两点的边。
弦图:任意长度大于
Lemma 1:团数
证明:考虑单独对最大团的导出子图进行染色,至少需要
Lemma 2:最大独立集数
证明:每个团中至多选择一个点。
Lemma 3:弦图的任意导出子图一定是弦图。
证明:如果弦图有导出子图不是弦图,说明在这个导出子图上存在大于
Lemma 4:弦图的任意导出子图一定不可能是一个点数大于
证明:一个点数大于
弦图的判定¶
问题描述¶
给定一个无向图,判断其是否为弦图。
点割集¶
对于图
Lemma 5:图关于
证明:若
Lemma 6:弦图上任意两点间的极小点割集的导出子图一定为一个团。
证明:极小点割集大小
否则,设极小点割集上有两点为
由于
若这条弦连接了
由此,可证弦图中每个极小点割集中的两点都有边直接相连,故性质得证。
单纯点¶
设
Lemma 7:任何一个弦图都至少有一个单纯点,不是完全图的弦图至少有两个不相邻的单纯点。
证明:数学归纳法。单独考虑每一连通块。
归纳基底:当图与完全图同构时,图上任意一点都是单纯点。当图的点数
若图上的点数
由于每次将整个图分成若干个连通块证明,大小一定减小,且都满足性质,故归纳成立。
完美消除序列¶
令
Lemma 8:一个无向图是弦图当且仅当其有一个完全消除序列。
充分性:点数为
必要性:假设有无向图存在结点数
朴素算法¶
每次找到一个 单纯点
将点
重复以上过程,若所有点都被删除,则原图是弦图且求得了一个完美消除序列;若图上不存在单纯点,则原图不是弦图。
时间复杂度
MCS 算法¶
最大势算法(Maximum Cardinality Search)是一种可以在
逆序给结点编号,即按从
设
用链表维护对于每个
由于每条边对
正确性证明:
设
Lemma 9:考虑三个点
Lemma 10:任意一个弦图一定不存在一个序列
v_iv_j |i-j|=1 \alpha(v_0)>\alpha(v_i)(i\in[1,k]) - 存在
i\in[1,k-1] \alpha(v_i)<\alpha(v_{i+1})<...<\alpha(v_k) \alpha(v_i)<\alpha(v_{i-1})<...<\alpha(v_1)<\alpha(v_k)<\alpha(v_0)
证明:
由于
考虑最小的
如果
在上面的推导中,我们扩大了
Theorem 1:对于任何一个弦图,最大势算法求出的序列一定是一个完美消除序列。
证明:考虑任意三个点
考虑反证法,假设不相连,那么
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | while (cur) {
p[cur] = h[nww];
rnk[p[cur]] = cur;
h[nww] = nxt[h[nww]];
lst[h[nww]] = 0;
lst[p[cur]] = nxt[p[cur]] = 0;
tf[p[cur]] = true;
for (vector<int>::iterator it = G[p[cur]].begin(); it != G[p[cur]].end();
it++)
if (!tf[*it]) {
if (h[deg[*it]] == *it) h[deg[*it]] = nxt[*it];
nxt[lst[*it]] = nxt[*it];
lst[nxt[*it]] = lst[*it];
lst[*it] = nxt[*it] = 0;
deg[*it]++;
nxt[*it] = h[deg[*it]];
lst[h[deg[*it]]] = *it;
h[deg[*it]] = *it;
}
cur--;
if (h[nww + 1]) nww++;
while (nww && !h[nww]) nww--;
}
|
如果此时原图是弦图,此时求出的就是完美消除序列;但是由于原图可能不是弦图,此时求出的一定不是完美消除序列,所以问题转化为 判断求出的序列是否是原图的完美消除序列。
判断一个序列是否是完美消除序列¶
朴素算法¶
根据定义,依次判断完美消除序列
优化后的算法¶
根据完美消除序列的定义,设
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | jud = true;
for (int i = 1; i <= n; i++) {
cur = 0;
for (vector<int>::iterator it = G[p[i]].begin(); it != G[p[i]].end(); it++)
if (rnk[p[i]] < rnk[*it]) {
s[++cur] = *it;
if (rnk[s[cur]] < rnk[s[1]]) swap(s[1], s[cur]);
}
for (int j = 2; j <= cur; j++)
if (!st[s[1]].count(s[j])) {
jud = false;
break;
}
}
if (!jud)
printf("Imperfect\n");
else
printf("Perfect\n");
|
至此,弦图判定问题 可以在
弦图的极大团¶
令
证明:考虑弦图的一个极大团
弦图最多有
设
设
问题转化为判断是否存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | for (int i = 1; i <= n; i++) {
cur = 0;
for (vector<int>::iterator it = G[p[i]].begin(); it != G[p[i]].end(); it++)
if (rnk[p[i]] < rnk[*it]) {
s[++cur] = *it;
if (rnk[s[cur]] < rnk[s[1]]) swap(s[1], s[cur]);
}
fst[p[i]] = s[1];
N[p[i]] = cur;
}
for (int i = 1; i <= n; i++) {
if (!vis[p[i]]) ans++;
if (N[p[i]] >= N[fst[p[i]]] + 1) vis[fst[p[i]]] = true;
}
|
弦图的色数/弦图的团数¶
一种构造方法:按完美消除序列从后往前依次给每个点染色,给每个点染上可以染的最小颜色。时间复杂度
正确性证明:设以上方法使用了
无需染色方案,只需求出弦图的色数/团数时,可以取
1 | for (int i = 1; i <= n; i++) ans = max(ans, deg[i] + 1);
|
弦图的最大独立集/最小团覆盖¶
最大独立集:完美消除序列从前往后,选择所有没有与已经选择的点有直接连边的点。
最小团覆盖:设最大独立集为
正确性证明:设以上方案独立集数和团覆盖数为
1 2 3 4 5 6 | for (int i = 1; i <= n; i++)
if (!vis[p[i]]) {
ans++;
for (vector<int>::iterator it = G[p[i]].begin(); it != G[p[i]].end(); it++)
vis[*it] = true;
}
|
习题¶
参考资料¶
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:OI-wiki
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用