【瞎口胡】弦图
弦图,我真的好喜欢你啊,为了你,我要求出你的完美消除序列!
本篇目参考 OI-Wiki,修改了部分证明。
定义#
弦图是满足以下条件的无向图:任意长度大于 的环上都有一条「弦」,即连接环上不相邻两点的边。
让我们明确以下新定义:
- 团:完全子图。
- 极大团:不是其它团子图的团。
- 最大团:点数最大的团。
- 团数:记作 ,表示最大团点数。
- 最小染色:使用最小的颜色对点进行染色使得相邻两点颜色不同。
- 色数:记作 ,表示最小染色使用的颜色数量。
- 最大独立集:记作 ,最大的内部没有连边的点集。
- 最小团覆盖:用最少的团覆盖所有点,使用的团的数量记为 。
- 邻域:记作 ,表示与一个点相邻的点构成的集合。
基本性质#
-
引理 1:团数 色数
考虑对最大团的导出子图进行染色,色数是 。
-
引理 2:最大独立集 最小团覆盖数
每个团最多选一个点。
-
引理 3:弦图的导出子图一定是弦图。
显然。
-
引理 4:弦图的导出子图一定不是点数大于 的环。
同引理 3。
点割集#
之间的点割集指的是一个点集,使得删掉它们后 不连通。最小点割集是满足条件的点集中,点数最小的。
-
引理 5:考虑删掉最小点割集 之后,原图分成了至少两个联通块。设包含 的联通块分别是 ,那么对于任意 ,一定存在 使得 。
-
引理 6:最小点割集 一定是一个团。
时是平凡的。对于 ,此时最小点割集上一定存在两点 ,设 在 中的点分别为 和 。
点对 和 之间有最短路。考虑 和 在路径上只经过 时的最短路,不难发现分别为 和 ,此时存在长度大于等于 的环 ,根据弦图的定义,该环上一定存在一条弦。
注意到,弦不能连接 中各一个点(否则不是点割集);也不能连接 内部的两个点(否则不是最短路); 更不能连接 内部的一个点和 中的某一个(同理)。因此,这条弦只能连接 。
于是对于任意 应用上述论述,我们得到了任意 之间都有边,于是它是一个团。
单纯点#
单纯点指的是满足以下条件的点 :它和它的邻域,即 构成一个团。
-
引理 7:任何一个弦图都有至少一个单纯点,不是完全图的弦图有至少两个不相邻的单纯点。
考虑对于每个联通块单独证明。
当图的大小 时,引理成立。
如果图的大小至少为 ,完全图的部分也平凡的。接下来,如果图不是完全图,则一定存在一条边 。设 是 间的最小点割集, 为删去 后 各自所在的联通块。
不失一般性,考虑 一侧,设 ,如果 是完全图,则 是单纯点;如果不是,那么 上有两个不相邻的单纯点。因为 是完全图,其上任意两点相邻,因此 上至少有一个单纯点。
考虑将 上的单纯点拓展到全图,如果邻域没有变化,那么它就是原图的一个单纯点。不难发现, 上每个点的邻域一定是 中的一部分点,因此拓展到全图后邻域没有变化。
对于 侧同样考虑,我们得到了两个不相邻的单纯点,引理 7 得证。
完美消除序列#
对于 个点的弦图,完美消除序列指的是这样一个序列 ,它满足对于每个 , 在 的导出子图中是单纯点。
-
引理 8:一个无向图是弦图当且仅当其存在完美消除序列。
考虑如果一个无向图是弦图,每次在点数为 的弦图的完美消除序列的最前方加入一个单纯点就可以得到点数为 的弦图的完美消除序列、
如果一个非弦图的无向图存在大小大于 的环但有完美消除序列,设在完美消除序列中出现的第一个在环上的点是 ,它在环上和 相邻,根据单纯点的性质可知 构成一个团,于是存在弦 ,矛盾。
-
MCS 最大势算法
考虑从 到 逆序给节点标号,设 表示和 相邻的已标号点数的数量,每次选出 最大且未被标号的节点进行标号。正确性显然。
一个图是弦图当且仅当求出的序列是完美消除序列。读者自证不难,我不会。
时间复杂度 (使用链表)或者多一个 。
应用#
重新定义 表示 的邻域中完美消除序列位置在自己之后的点的数量。
-
找最大团
最大的 。
-
色数
按完美消除序列从后往前依次给每个点染色,给每个点染上可以染的最小颜色。
考虑此时方案数 ,且瓶颈在于最大团上的染色,因此 ,由引理 1得,因此 。
就是最大团大小。
-
最大独立集 / 最小团覆盖
最大独立集:完美消除序列从前往后,选择所有没有与已经选择的点有直接连边的点。
最小团覆盖:独立集中的每个点和邻域构成的团,即 。
设上面的方法求出的答案为 ,那么 ,引理 2 得 ,于是 。
例题 1 [HNOI2008]神奇的国度#
题意
求弦图色数。
题解
按照结论模拟即可。
# include <bits/stdc++.h>
const int N=10010,INF=0x3f3f3f3f;
struct Node{
int id,w;
bool operator < (const Node &rhs) const{
return w<rhs.w;
}
};
std::priority_queue <Node> Q;
std::vector <int> G[N];
int n,m;
int rk[N],p[N],lb[N];
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-') f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
int main(void){
n=read(),m=read();
for(int i=1;i<=m;++i){
int u=read(),v=read();
G[u].push_back(v),G[v].push_back(u);
}
for(int i=1;i<=n;++i) Q.push((Node){i,0});
int cur=n;
while(!Q.empty()){
int i=Q.top().id;
Q.pop();
if(rk[i]) continue;
rk[i]=cur,p[cur]=i,--cur;
for(auto v:G[i]){
if(!rk[v]) ++lb[v],Q.push((Node){v,lb[v]});
}
} // MCS 算法
int mx=0;
for(int i=1;i<=n;++i){
int cur=1;
for(auto v:G[i]) if(rk[i]<rk[v]) ++cur;
mx=std::max(mx,cur);
}
printf("%d",mx);
return 0;
}
例题 2 [TJOI2007]小朋友#
题意
求弦图最大独立集。
题解
按照题意模拟即可。
# include <bits/stdc++.h>
const int N=210,INF=0x3f3f3f3f;
struct Node{
int id,w;
bool operator < (const Node &rhs) const{
return w<rhs.w;
}
};
std::priority_queue <Node> Q;
std::vector <int> G[N];
int n,m;
int rk[N],p[N],lb[N];
bool vis[N];
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-') f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
int main(void){
n=read(),m=read();
for(int i=1;i<=m;++i){
int u=read(),v=read();
G[u].push_back(v),G[v].push_back(u);
}
for(int i=1;i<=n;++i) Q.push((Node){i,0});
int cur=n;
while(!Q.empty()){
int i=Q.top().id;
Q.pop();
if(rk[i]) continue;
rk[i]=cur,p[cur]=i,--cur;
for(auto v:G[i]){
if(!rk[v]) ++lb[v],Q.push((Node){v,lb[v]});
}
}
int mx=0;
for(int i=1;i<=n;++i){
if(vis[p[i]]) continue;
++mx,vis[p[i]]=true;
for(auto v:G[p[i]]) if(rk[p[i]]<rk[v]) vis[v]=true;
}
printf("%d",mx);
return 0;
}
作者:Meatherm
出处:https://www.cnblogs.com/Meatherm/p/16626612.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!