弦图与区间图总结-DZYO(定义)
弦图 完美消除序列 MCS算法(代码)
省选前为什么要开这种奇奇怪怪的知识点
具体定义和证明较略,主要记录实现方法。
弦就是连接环上两个不相邻点的边。弦图满足图中任意长度>3的环都至少有一个弦(递归下去就是一个三角剖分的图)
单纯点:
点 v v v是单纯点当且仅当 v v v和其相邻的点集 N ( v ) N(v) N(v)构成的原图的诱导子图是完全图。
普通图:
最大团数 ≤ \leq ≤最小色数
最大独立集 ≤ \leq ≤最小团覆盖
弦图:
最大团数=最小色数
最大独立集=最小团覆盖
完美消除序列:
原图的一个点序列 v 1 , v 2 , . . . , v n v_1,v_2,...,v_n v1,v2,...,vn(每个点都出现恰好一次),满足 v i v_i vi在 v i , v i + 1 , . . . , v n v_i,v_{i+1},...,v_n vi,vi+1,...,vn的诱导子图中为一个单纯点。
定理:一个无向图是弦图当且仅当它有一个完美消除序列。
由定理:“一个无向图是弦图当且仅当它有一个完美消除序列”。
考虑求出一个序列并验证其是否为完美消除序列。
最大势算法MCS
倒序求出 v n , . . . , v 1 v_n,...,v_1 vn,...,v1(逐个标出 n − 1 n-1 n−1),设 f i f_i fi表示点 i i i与多少个已标号点相邻,每次选 f i f_i fi最大的未标号点标号。
验证是否为完美消除序列:
设 v i + 1 , . . . , v n v_{i+1},...,v_n vi+1,...,vn中与 v i v_i vi相邻的下标最小( v v v中排列最靠前)点为 v j v_j vj,只需要判断 v j v_j vj是否与其后所有与 v i v_i vi相邻的点相邻即可。
复杂度 O ( n + m ) O(n+m) O(n+m)
n n n比较小时,可以邻接矩阵判边的存在性。
//bzoj1242 Zju1015 Fishing Net弦图判定
#include
#define pb push_back
using namespace std;
const int N=1010,M=4e6+10;
int n,m,g[N][N],q[N],f[N],rk[N];
int head[N],to[M],nxt[M],tot;
vector<int>nt[N];bool vs[N];
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void MSC()
{
int i,j,x,y,bst=0;
for(i=1;i<=n;++i) lk(0,i);
for(j=n;j>0;--j){
for(;;){
for(int &i=head[bst];i;i=nxt[i])
if(!vs[to[i]]) break;
if(head[bst]){
x=to[head[bst]];q[j]=x;rk[x]=j;vs[x]=true;
for(i=nt[x].size()-1;i>=0;--i) if(!vs[nt[x][i]]){
y=nt[x][i];f[y]++;lk(f[y],y);
bst=max(bst,f[y]);
}
break;
}else bst--;
}
}
}
int stk[N],top;
bool ck()
{
int i,j,x,y,mng,mnv;
for(j=n;j>0;--j){
x=q[j];top=0;mng=n+1;
for(i=nt[x].size()-1;i>=0;--i) if(rk[nt[x][i]]>j){
y=nt[x][i];stk[++top]=y;
if(rk[y]<mng) mng=rk[y],mnv=y;
}
if(mng==n+1) continue;
for(i=1;i<=top;++i) if(stk[i]!=mnv)
if(!g[mnv][stk[i]]) return false;
}
return true;
}
int main(){
int i,j,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i){
scanf("%d%d",&x,&y);
g[x][y]=g[y][x]=1;
nt[x].pb(y);nt[y].pb(x);
}
MSC();
if(ck()) printf("Perfect");
else printf("Imperfect");
return 0;
}
同样MCS求出完美消除序列
倒序处理 v n , . . . , v 1 v_n,...,v_1 vn,...,v1的染色,求出最小的没有被 v i v_i vi已染色相邻点( v v v中排名比它大)取的颜色 k k k,设 c o l [ v i ] = k col[v_i]=k col[vi]=k即可。
//bzoj1006 [HNOI2008]神奇的国度 弦图最小染色
#include
#define pb push_back
using namespace std;
const int N=10010,M=4e6+10;
int n,m,q[N],f[N],ans,col[N],tg[N];
int head[N],to[M],nxt[M],tot;
vector<int>nt[N];bool vs[N];
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void MSC()
{
int i,j,x,y,bst=0;
for(i=1;i<=n;++i) lk(0,i);
for(j=n;j>0;--j){
for(;;){
for(int &i=head[bst];i;i=nxt[i])
if(!vs[to[i]]) break;
if(head[bst]){
x=to[head[bst]];q[j]=x;vs[x]=true;
for(i=nt[x].size()-1;i>=0;--i) if(!vs[nt[x][i]]){
y=nt[x][i];f[y]++;lk(f[y],y);
bst=max(bst,f[y]);
}
break;
}else bst--;
}
}
}
int main(){
int i,j,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i){
scanf("%d%d",&x,&y);
nt[x].pb(y);nt[y].pb(x);
}
MSC();
for(j=n;j>0;--j){
x=q[j];
for(i=nt[x].size()-1;i>=0;--i) tg[col[nt[x][i]]]=x;
for(i=1;tg[i]==x;++i);col[x]=i;ans=max(ans,i);
}
printf("%d",ans);
return 0;
}