Loading

【瞎口胡】弦图

弦图,我真的好喜欢你啊,为了你,我要求出你的完美消除序列!

本篇目参考 OI-Wiki,修改了部分证明。

定义

弦图是满足以下条件的无向图:任意长度大于 \(3\) 的环上都有一条「」,即连接环上不相邻两点的边。

让我们明确以下新定义:

  • :完全子图。
  • 极大团:不是其它团子图的团。
  • 最大团:点数最大的团。
  • 团数:记作 \(\omega (G)\),表示最大团点数。
  • 最小染色:使用最小的颜色对点进行染色使得相邻两点颜色不同。
  • 色数:记作 \(\chi(G)\),表示最小染色使用的颜色数量。
  • 最大独立集:记作 \(\alpha(G)\),最大的内部没有连边的点集。
  • 最小团覆盖:用最少的团覆盖所有点,使用的团的数量记为 \(\kappa (G)\)
  • 邻域:记作 \(N(x)\),表示与一个点相邻的点构成的集合。

基本性质

  • 引理 1:团数 \(\omega (G) \leq \chi (G)\) 色数

    考虑对最大团的导出子图进行染色,色数是 \(\omega(G)\)

  • 引理 2:最大独立集 \(\alpha(G) \leq \kappa(G)\) 最小团覆盖数

    每个团最多选一个点。

  • 引理 3:弦图的导出子图一定是弦图。

    显然。

  • 引理 4:弦图的导出子图一定不是点数大于 \(3\) 的环。

    同引理 3。

点割集

\(u,v\) 之间的点割集指的是一个点集,使得删掉它们后 \(u,v\) 不连通。最小点割集是满足条件的点集中,点数最小的。

  • 引理 5:考虑删掉最小点割集 \(S\) 之后,原图分成了至少两个联通块。设包含 \(u,v\) 的联通块分别是 \(V_1,V_2\),那么对于任意 \(a \in S\),一定存在 \(x,y \in N(a)\) 使得 \(x \in V_1,y \in V_2\)

  • 引理 6:最小点割集 \(S\) 一定是一个团。

    \(|S|\leq 1\) 时是平凡的。对于 \(|S|>1\),此时最小点割集上一定存在两点 \(x,y\),设 \(N(x),N(y)\)\(V_1,V_2\) 中的点分别为 \(x_1,x_2\)\(y_1,y_2\)

    点对 \((x_1,y_1)\)\((x_2,y_2)\) 之间有最短路。考虑 \(x\)\(y\) 在路径上只经过 \(V_1,V_2\) 时的最短路,不难发现分别为 \(x \to x_1 \to \cdots \to y_1 \to y\)\(x \to x_2 \to \cdots \to y_2 \to y\),此时存在长度大于等于 \(4\) 的环 \(x \to x_1 \cdots \to y_1 \to y \to y_2 \to \cdots \to x_2 \to x\),根据弦图的定义,该环上一定存在一条弦。

    注意到,弦不能连接 \(V_1,V_2\) 中各一个点(否则不是点割集);也不能连接 \(V_1,V_2\) 内部的两个点(否则不是最短路); 更不能连接 \(V_1,V_2\) 内部的一个点和 \(x,y\) 中的某一个(同理)。因此,这条弦只能连接 \(x,y\)

    于是对于任意 \(x,y\) 应用上述论述,我们得到了任意 \(x,y\) 之间都有边,于是它是一个团。

单纯点

单纯点指的是满足以下条件的点 \(x\):它和它的邻域,即 \(\{x\}+N(x)\)构成一个团。

  • 引理 7:任何一个弦图都有至少一个单纯点,不是完全图的弦图有至少两个不相邻的单纯点。

    考虑对于每个联通块单独证明。

    当图的大小 \(\leq 3\) 时,引理成立。

    如果图的大小至少为 \(4\),完全图的部分也平凡的。接下来,如果图不是完全图,则一定存在一条边 \((u,v) \notin E\)。设 \(I\)\(u,v\) 间的最小点割集,\(A,B\) 为删去 \(I\)\(u,v\) 各自所在的联通块。

    不失一般性,考虑 \(A\) 一侧,设 \(L=A+I\),如果 \(L\) 是完全图,则 \(u\) 是单纯点;如果不是,那么 \(L\) 上有两个不相邻的单纯点。因为 \(I\) 是完全图,其上任意两点相邻,因此 \(A\) 上至少有一个单纯点。

    考虑将 \(A\) 上的单纯点拓展到全图,如果邻域没有变化,那么它就是原图的一个单纯点。不难发现,\(A\) 上每个点的邻域一定是 \(L\) 中的一部分点,因此拓展到全图后邻域没有变化。

    对于 \(B\) 侧同样考虑,我们得到了两个不相邻的单纯点,引理 7 得证。

完美消除序列

对于 \(n\) 个点的弦图,完美消除序列指的是这样一个序列 \(v_1,v_1,\cdots,v_n\),它满足对于每个 \(i\)\(v_i\)\(\{v_i,v_i+1,\cdots,v_n\}\) 的导出子图中是单纯点。

  • 引理 8:一个无向图是弦图当且仅当其存在完美消除序列。

    考虑如果一个无向图是弦图,每次在点数为 \(n-1\) 的弦图的完美消除序列的最前方加入一个单纯点就可以得到点数为 \(n\) 的弦图的完美消除序列、

    如果一个非弦图的无向图存在大小大于 \(3\) 的环但有完美消除序列,设在完美消除序列中出现的第一个在环上的点是 \(v\),它在环上和 \(v_1,v_2\) 相邻,根据单纯点的性质可知 \(v,v_1,v_2\) 构成一个团,于是存在弦 \((v_1,v_2)\),矛盾。

  • MCS 最大势算法

    考虑从 \(n\)\(1\) 逆序给节点标号,设 \(l_x\) 表示和 \(x\) 相邻的已标号点数的数量,每次选出 \(l\) 最大且未被标号的节点进行标号。正确性显然。

    一个图是弦图当且仅当求出的序列是完美消除序列。读者自证不难,我不会。

    时间复杂度 \(O(n+m)\)(使用链表)或者多一个 \(\log\)

应用

重新定义 \(N(x)\) 表示 \(x\) 的邻域中完美消除序列位置在自己之后的点的数量。

  • 找最大团

    最大的 \(\{x\}+N(x)\)

  • 色数

    按完美消除序列从后往前依次给每个点染色,给每个点染上可以染的最小颜色。

    考虑此时方案数 \(t \geq \chi(G)\),且瓶颈在于最大团上的染色,因此 \(t=\omega(G)\),由引理 1得\(t \leq \chi(G)\),因此 \(t = \chi (G)\)

    \(\chi(G)\) 就是最大团大小。

  • 最大独立集 / 最小团覆盖

    最大独立集:完美消除序列从前往后,选择所有没有与已经选择的点有直接连边的点。

    最小团覆盖:独立集中的每个点和邻域构成的团,即 \(\{\{u_1\}+N(u_1),\cdots\{u_{t}\}+N(u_{t})\}\)

    设上面的方法求出的答案为 \(t\),那么 \(\kappa(G) \leq t \leq \alpha(G)\),引理 2 得 \(\alpha(G) \leq \kappa (G)\),于是 \(\alpha(G) = \kappa(G) = t\)

例题 1 [HNOI2008]神奇的国度

题意

求弦图色数。

\(1 \leq n \leq 10^4. 1 \leq m \leq 10^6\)

题解

按照结论模拟即可。

# 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]小朋友

题意

求弦图最大独立集。

\(1 \leq n \leq 200,0 \leq m \leq \dfrac{n(n-1)}{2}\)

题解

按照题意模拟即可。

# 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;
}
posted @ 2022-08-26 09:59  Meatherm  阅读(159)  评论(2编辑  收藏  举报