弦图 完美消除序列 MCS算法

对于普通图的两个性质:

最大团数 ≤ 最小色数

最大独立集 ≤ 最小团覆盖

而在弦图就变成了:

最大团数=最小色数

最大独立集=最小团覆盖

(虽然不知道有什么用

完美消除序列:

对与序列中的点vi,排在vi后面并且和vi相连的点是一个团

一个图存在完美消除序列是它是弦图的充要条件

那么完美消除序列有什么用呢?用处可大啦

求弦图的最大团数/最小色数的时候,只要在完美消除序列上从后往前贪心染色即可。

而求最大独立集/最小团覆盖的时候,只要在完美消除序列上从前往后贪心取点即可。



那么就来了一系列的问题,首先是弦图的判定,我们需要确定这个图有没有完美消除序列。

MCS算法

从后往前确定序列的点,每取一个点都把还没加入序列的和它相连的点的标号+1,每次取点选择标号最大的点之一。

具体实现好难描述不想说了= =下面有代码,复杂度O(m+n)

据说如果图是弦图,这个算法求出来的序列可以保证是完美消除序列

那么当我们需要判定弦图的时候,就要判断这个序列是不是完美消除序列了。

判断的方法是:

从后往前确定序列中的每个点v是否满足条件:排在v后面的和v相连的点集记为N(v)中排在最前的点记为next(v)是否和N(v)中其他点都相连。

具体实现是,点数少的话直接拿邻接矩阵判相连O(m+n),点数多就把边表排序然后二分O(mlogm+n)。



至此我们已经知道如何解决弦图判定问题和如何求完美消除序列了,那么现在看看具体例题

zoj1015:

裸的弦图判定,点数1000,直接按照上面的做法瞎搞即可

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iomanip>
#include<vector>
#include<set>
#include<map>
#include<queue>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

#define rep(i,k,n) for(int i=(k);i<=(n);i++)
#define rep0(i,n) for(int i=0;i<(n);i++)
#define red(i,k,n) for(int i=(k);i>=(n);i--)
#define sqr(x) ((x)*(x))
#define clr(x,y) memset((x),(y),sizeof(x))
#define pb push_back
#define mod 1000000007
const int maxn=1010;
const int maxm=3500010;

struct List
{
    int v,next;
}list[maxm];
int eh[maxn],tot,mh[maxn];

inline void add(int h[],int u,int v)
{
    list[tot].v=v;
    list[tot].next=h[u];
    h[u]=tot++;
}

int n,m,best;
int q[maxn],f[maxn],g[maxn];
bool vis[maxn];

void MCS()
{
    clr(mh,-1);clr(vis,0);clr(f,0);
    for(int i=1;i<=n;i++)add(mh,0,i);
    best=0;
    for(int j=n;j;j--)
    {
        while(1)
        {
            int i;
            for(i=mh[best];~i;i=list[i].next)
            {
                if(!vis[list[i].v])break;
                else mh[best]=list[i].next;
            }
            if(~i)
            {
                int x=list[i].v;
                q[j]=x;g[x]=j;
                vis[x]=1;
                for(i=eh[x];~i;i=list[i].next)if(!vis[list[i].v])
                {
                    f[list[i].v]++;
                    add(mh,f[list[i].v],list[i].v);
                    best=max(best,f[list[i].v]);
                }
                break;
            }
            else best--;
        }
    }
}

int st[maxn],top;
bool e[maxn][maxn];

bool checkq()
{
    for(int j=n-1;j;j--)
    {
        int u=q[j];
        top=0;
        int ming=n+1,minv;
        for(int i=eh[u];~i;i=list[i].next)if(g[list[i].v]>j)
        {
            st[++top]=list[i].v;
            if(g[list[i].v]<ming)
            {
                ming=g[list[i].v];
                minv=list[i].v;
            }
        }
        if(ming==n+1)continue;
        for(int i=1;i<=top;i++)if(st[i]!=minv)
        {
            if(!e[minv][st[i]])return 0;
        }
    }
    return 1;
}

int main()
{
    while(scanf("%d%d",&n,&m),n)
    {
        clr(eh,-1);tot=0;
        clr(e,0);

        int u,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(eh,u,v);
            add(eh,v,u);
            e[u][v]=e[v][u]=1;
        }

        MCS();
        puts(checkq()?"Perfect":"Imperfect");
        puts("");
    }

    return 0;
}

bzoj1006:

裸的弦图的最小染色数,直接按照上面做法瞎搞即可

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iomanip>
#include<vector>
#include<set>
#include<map>
#include<queue>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

#define rep(i,k,n) for(int i=(k);i<=(n);i++)
#define rep0(i,n) for(int i=0;i<(n);i++)
#define red(i,k,n) for(int i=(k);i>=(n);i--)
#define sqr(x) ((x)*(x))
#define clr(x,y) memset((x),(y),sizeof(x))
#define pb push_back
#define mod 1000000007
const int maxn=10010;
const int maxm=4000010;

struct List
{
    int v,next;
}list[maxm];
int eh[maxn],tot,mh[maxn];

inline void add(int h[],int u,int v)
{
    list[tot].v=v;
    list[tot].next=h[u];
    h[u]=tot++;
}

int n,m,best,q[maxn],f[maxn],color[maxn],mark[maxn];
bool vis[maxn];

void MCS()
{
    clr(mh,-1);clr(vis,0);clr(f,0);
    rep(i,1,n)add(mh,0,i);
    best=0;
    red(j,n,1)
    {
        while(1)
        {
            int i;
            for(i=mh[best];~i;i=list[i].next)
            {
                if(!vis[list[i].v])break;
                else mh[best]=list[i].next;
            }
            if(~i)
            {
                int x=list[i].v;
                q[j]=x;vis[x]=1;
                for(i=eh[x];~i;i=list[i].next)
                {
                    int v=list[i].v;
                    if(vis[v])continue;
                    f[v]++;
                    add(mh,f[v],v);
                    best=max(best,f[v]);
                }
                break;
            }
            else best--;
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    int u,v;
    clr(eh,-1);tot=0;
    rep(i,1,m)
    {
        scanf("%d%d",&u,&v);
        add(eh,u,v);
        add(eh,v,u);
    }
    MCS();
    clr(mark,0);clr(color,0);
    int ans=0;
    red(j,n,1)
    {
        for(int i=eh[q[j]];~i;i=list[i].next)mark[color[list[i].v]]=j;
        int i;
        for(i=1;mark[i]==j;i++);
        color[q[j]]=i;
        ans=max(ans,i);
    }
    printf("%d\n",ans);

    return 0;
}

具体求最大独立集和最小团覆盖主要还是求完美消除序列,剩下的东西也差不多,暂时也没找到题目,就不详细说啦

另外,还有找弦图所有极大团的问题。这里就要用到上面说的N(v)和next(v), 显然极大团一定是v∪N(v)的形式,那么判断它是不是极大团只要判断是否存在一个w,满足 next(w)=v 且 |N(v)|+1≤|N(w)|

据说复杂度是O(m+n)暂时没研究过不清楚。。。

时间: 2024-10-22 10:35:45

弦图 完美消除序列 MCS算法的相关文章

bzoj 1006: [HNOI2008]神奇的国度 弦图的染色问题&amp;&amp;弦图的完美消除序列

1006: [HNOI2008]神奇的国度 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1788  Solved: 775[Submit][Status] Description K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人 A1A2...An之间仅存在N对认识关系:(A1A2)

无向图的完美消除序列 判断弦图 ZOJ 1015 Fish net

   ZOJ1015 题意简述:给定一个无向图,判断是否存在一个长度大于3的环路,且其上没有弦(连接环上不同两点的边且不在环上). 命题等价于该图是否存在完美消除序列. 所谓完美消除序列:在 vi,vi+1,...vn vi与之后与vi相邻的点构成一个团(完全子图). 求完美消除序列的MCS算法.倒序给点标号,标号为i的点出现在序列的第i项.对每个顶点i,维护标号label[i],表示标号的度,每次选择标号最大的点标号.用堆加速. 求出了完美消除序列后,只要判断这个序列是否合法就可以得出结论.

关于弦图一些问题的解法

完美消除序列($MCS$算法): 每个点记录一个势,表示与它相邻的已经在完美消除序列的点的个数. 先把$n$号点弄出来,然后每次把势最大的弄出来,这样依次求出的点的逆序就是完美消除序列,使用链表或动态数组可以让复杂度降至$O(n)$. 代码: 1 for (RG int i=1;i<=n;++i) ep[0].push_back(i); 2 for (RG int i=n,now;i;--i){ 3 while (1){ 4 now=ep[best].back(); if (!l[now]) b

ZOJ 1015 Fishing Net 弦图MCS

一个无向图是弦图当且仅当有一个完美消除序列. MCS最大势:http://wenku.baidu.com/view/07f4be196c175f0e7cd13784.html Fishing Net Time Limit: 10 Seconds      Memory Limit: 32768 KB In a highly modernized fishing village, inhabitants there make a living on fishery. Their major too

[BZOJ 1006] [HNOI2008] 神奇的国度 【弦图最小染色】

题目链接: BZOJ - 1006 题目分析 这道题是一个弦图最小染色数的裸的模型. 弦图的最小染色求法,先求出弦图的完美消除序列(MCS算法),再按照完美消除序列,从后向前倒着,给每个点染能染的最小颜色. 求出的颜色数就是最小染色,同时也是最大团. 代码 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <cstring> #in

ZOJ 1015 Fishing Net(弦图判定)

In a highly modernized fishing village, inhabitants there make a living on fishery. Their major tools, fishing nets, are produced and fixed by computer. After catching fishes each time, together with plenty of fishes, they will bring back the shabby

BZOJ 1006: [HNOI2008]神奇的国度(弦图染色)

http://www.lydsy.com/JudgeOnline/problem.php?id=1006 题意: 思路: 这个就是弦图染色问题,弦图啥的反正我也不懂,具体看论文https://wenku.baidu.com/view/07f4be196c175f0e7cd13784.html 这里的话就是用最大势算法求了一个完美消除序列,然后根据完美消除序列来进行染色即可. 1 #include<iostream> 2 #include<algorithm> 3 #include&

[BZOJ1006] [HNOI2008] 神奇的国度 (弦图)

Description K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人 A1A2...An之间仅存在N对认识关系:(A1A2)(A2A3)...(AnA1),而没有其它认识关系.比如四边关系指ABCD四个人 AB,BC,CD,DA相互认识,而AC,BD不认识.全民比赛时,为了防止做弊,规定任意一对相互认识的人不得在一队,国王相知道,

弦图与区间图

原来想把论文里面所有没证的东西都证一遍,结果发现我太弱证不了[捂脸熊]那就把一些结论记一下吧QAQ以后有什么兴趣的话再来补证明 一些定义什么的自行脑补吧 1.对任意的一张图来说,团数<=色数,最大独立集数<=最小团覆盖数.当图是弦图的时候这两个式子都取到了等号. 2.一张图是弦图当且仅当它有一个完美消除序列. 3.最大势算法(MCS)求一张弦图的完美消除序列.从n到1的顺序给每个点标号,设label[i]表示i与多少个已经标号的节点标号.那么每次选择label[i]最大点进行标号. mlogn