弦图 学习笔记
弦图 学习笔记
定义
弦图中任意 \(k\ge 4\) 阶环都有弦,等价于对于任意导出子图都不是 \(k\ge 4\) 阶环。
单纯点
单纯点的邻域是团。
完美消除序列(aka peo)
点的排列,使得 \(\forall i, v_i\) 在 \(\{v_i, v_{i + 1}, ..., v_n\}\) 的诱导子图中是单纯点。
点割集
\((u, v)\) 的点割集是点集,使得删除点割集之后的诱导子图中 \(u, v\) 不连通。
性质
- 弦图的诱导子图是弦图(Lemma 1)。
- 弦图中 \((u, v)\) 的极小点割集 \(A\) 是团(Lemma 2)。
证明:
设删去点割集之后 \(u, v\) 所在连通块是 \(V_1, V_2\)。
观察:点割集中任意点与 \(V_1, V_2\) 有连边(否则可以删去此点)。
对于点割集中任意两点 \(x, y\),存在 \(x_1, y_1\in V_1\) 且与 \(x, y\) 相邻,同理 \(x_2, y_2\)。
则找到 \(x_1 \rightarrow y_1, y_2\rightarrow x_2\) 的最短路,此时形成环,若 \(x, y\) 无边则不是弦图,得证。
- 弦图有至少一个单纯点,且非完全图有至少 2 个不相邻单纯点(Lemma 3)。
证明:
归纳。
任取不相邻 \(u, v\),由于对称,证明 \(V_1\) 有一个单纯点即可。
如果 \(V_1\) 是团,显然成立,否则根据归纳假设,\(V_1\cup A\) 中有二不相邻单纯点,其中必有一个在 \(V_1\) 中,证毕。
- 图 \(G\) 是弦图当且仅当 \(G\) 拥有完美消除序列。
证明:必要性显然。
充分性:根据 Lemma 1,3,不断选取弦图中的单纯点即可。
求完美消除序列
- LEX-BFS 算法
从后往前确定 peo,先随便选一个点作为 BFS 起点,然后每次选取一个点,使得它邻域中已确定 peo 的点的 peo 字典序最大。
需要用点集分裂的思想,维护链表套链表,可以做到 \(O(n + m)\)。
正确性证明:
如果对于 \(i\) 的邻点 \(i_1, i_2\) 他们的 peo 在 \(i\) 后面,假设 \(i_1, i_2\) 无边。
则一定存在 \(i_3\) 使得与 \(i_1\) 相邻而不与 \(i\) 相邻,此时 \(i_2, i_3\) 无边否则非弦图,则可以如此构造下去,peo是无限序列,假设不成立,得证。
- MCS 算法
每次选取邻域被确定点最多的点。
可以简单地用优先队列带个 log 或用桶做到线性。
判定弦图
定义 \(u\) 邻域为 peo 在 \(u\) 后面且与 \(u\) 相邻的点集。
求出完美消除序列,从后往前类似归纳地每次对于一个点 \(u\),选择它最近的邻域点,判断此点邻域是否被 \(N(u)\) 包含。
NP-Hard 问题在弦图上的解决
- 最大团,\(\omega(G)\)
- 色数,\(\omega(G) \le X(G)\)
- 最大独立集,\(\alpha (G)\)
- 最小团覆盖,\(\alpha(G)\le K(G)\)。
在弦图中这些不等式都取等号。
- 色数
从后往前对peo贪心,每点颜色取邻域色 \(\text{mex}\)。
- 最大独立集
从前往后对peo贪心,每次给邻域打标记。
- 求所有极大团
观察:极大团是 \(v\cup N(v)\) 形式的。
则考虑标记非极大团。
对于 \(u\),定义 \(C(u) = u\cup N(u)\),若 \(\exists v, v < u, C(v)\supseteq C(u)\),则 \(u\) 非极大团。
等价于 $\exists w, w < u, u = \text{arcmin} N(w), C(w)\supseteq C(u) $,则 \(u\) 非极大团。
等价于 \(\exists w, w < u, u = \text{arcmin} N(w), |N(w)| = |N(u)| + 1\),则 \(u\) 非极大团。
根据以上引理可以得到求出所有极大团的线性算法,即从前往后扫,打标记。
例题
- SP5446 FISHNET - Fishing Net
判定是否是弦图,已在上文阐述。
- bzoj#P3103. Palindromic Equivalence
相当于计数回文串等价的方案数,考虑 manacher 的过程,对原串做一遍 manacher,manacher 上一对相等的,被拓展的字符相当于一对要求必须相等的关系,而停止拓展的一对字符相当于一对必须不等的关系,相等的关系直接用并查集合并起来,不等的关系建图。
观察到不会存在四元环,因为不等关系不会互相包含,所以这张图是弦图,原问题等价于弦图上染色的方案数,实际上 \(1, 2, 3, ..., n\) 就是一个完美消除序列,按照这个顺序结合前文 NP-Hard 问题在弦图上的解决 即可完成本题。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
//#define int long long
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 7;
int n, d[N], fa[N];
vector<int> g[N];
string s, t;
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int a, int b) {
int x = find(a), y = find(b);
if(x == y) return ;
fa[x] = y;
}
void manacher() {
n = t.size() - 1;
for(int i = 0; i <= n; i ++) fa[i] = i;
for(int i = 1, l, r; i <= n; i ++) {
if(i <= r) d[i] = min(r - i + 1, d[r - i + l]);
while(t[d[i] + i] == t[i - d[i]]) merge(i - d[i], i + d[i]), d[i] ++;
if(i + d[i] - 1 > r) l = i - d[i] + 1, r = i + d[i] - 1;
}
}
bool ok[N], st[N];
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> s, t = " ";
for(int i = 0; i < s.size(); i ++)
t += s[i], t += '#';
t += '$';
manacher();
for(int i = 1; i <= n; i ++)
if(find(i + d[i]) != find(i - d[i])) g[find(i + d[i])].push_back(find(i - d[i])), g[find(i - d[i])].push_back(find(i + d[i]));
int ans = 1;
for(int i = n; i; i --) {
if(fa[i] == i && isalpha(t[i])) {
int cnt = 26;
for(auto v : g[i])
if(ok[v] && !st[v])
cnt --, st[v] = 1;
ok[i] = 1;
ans = 1ll * ans * cnt % mod;
for(auto v : g[i])
if(ok[v]) st[v] = 0;
}
}
cout << ans << '\n';
return 0;
}

困难的

浙公网安备 33010602011771号