弦图
首先是弦的定义:
连接换上两个不相邻节点的边称为弦。
定义和数学中一个圆的弦比较像。
然后是弦图的定义:
若一张无向图中任意一个大小超过3的环都存在至少一条弦,那么这样的图称为弦图。
单纯点:
与其相邻的点集的诱导子图(把所以的边都连上后生成的图)是一个团(任两个点之间都有边)。
完美消除序列:
一个点的排列(v_1,v_2...v_n)满足(v_i)在${ v_i,v_{i+1}...v_n} $的诱导子图中为一个单纯点。
定理:一个无向图是弦图当且仅当它有一个完美消除序列。
用最大势算法((Maximum Cardinality Search))可以在(O(n+m))内求出一个消除序列的反序。
只要倒过来就可以了。
for (int i=n,now;i;--i)
{
bool fg=0;
while (!fg)
{
for (int j=v[best].size()-1;j>=0;--j)
if (!vis[v[best][j]]) {fg=1;now=v[best][j];break;}
else v[best].pop_back();
if (!fg) --best;
}
seq[i]=now;rk[now]=i;vis[now]=1;
for (int e=head[now];e;e=nxt[e])
if (!vis[to[e]])
{
v[++label[to[e]]].push_back(to[e]);
best=max(best,label[to[e]]);
}
}
弦图的判定
朴素算法(O(nm)=O(n^3))
优化算法:设({ v_{i+1}...v_n })中所有与(v_i)相邻的点依次为(v_{j_1}...v_{j_k})。
只需判断(v_{j_1})是否与(v_{j_2}...v_{j_k})相邻即可。
时间复杂度: (O(n+m)=O(n^2))
for (int i=1;i<=n;++i)
{
top=0;
for (int e=head[seq[i]];e;e=nxt[e])
if (rk[to[e]]<i) s[++top]=to[e];
for (int j=2;j<=top;++j)
if (!g[s[1]][s[j]]) ans=0;
}
最小色数问题
等于最小团数,也就是(max_{i=1}^{n}label[i]+1)
最大独立集
等于最小团覆盖数。按照完美消除序列一个个贪心选取即可。
我目前就只会这么多,其他的就以后再补吧。