zoukankan      html  css  js  c++  java
  • 弦图和区间图

    一直想看CDQ的课件,但是一直畏惧课件的长度没敢看,今天终于看完啦

    还是很简单的嘛        八月份!三个月!吼吼!

    做一些总结吧,以下是本人的理解:

    1、设图的点集为V,边集为E

    则其诱导子图的点集为V‘,边集为E’

    满足V‘属于V,E’属于E,且E‘中任意边的两个端点均属于V’

    2、弦是一个环中不在环上的且连接环上两点的边

    弦图中任意长度>3的环一定存在至少一条弦

    换句话说,弦图中最多只有三元环,其余的大环都是小环凑成的

    3、团:若对于任意两点u,v属于V,都存在(u,v)属于E

    则称这个图为一个团

    4、单纯点:设点u,跟u相连的点为N(u)

    若存在V‘=u U N(u),使得形成的原图的诱导子图是一个团

    则称u是一个单纯点

    5、完美消除序列:设V的一个排列{v1,……,vn}

    使得任意一个下标i均满足vi在{vi,……vn}的诱导子图是一个单纯点的序列

    我们称之为完美消除序列

    6、如何判断一个图是否是弦图

    定理:一个图是弦图当且仅当它有一个完美消除序列

    证明大略:

    充分性

    先证明弦图至少有一个单纯点和弦图的诱导子图也是弦图

    之后运用数学归纳法假设<n的弦图具有完美消除序列,则当前的弦图的完美消除序列可以通过一个单纯点和<n的弦图的完美消除序列得到

    必要性

    设一个图不是弦图,那这个图至少存在一个>3的小环

    设v,v1,v2是环上三点,v和v1,v2相连,v1和v2不相连(长度>3)

    设v在完美消除序列中第一次出现,由于v1和v2不相连,所以v不是{v,……,vn}的单纯点

    对于充分性的证明可以启发我们采用MCS算法来求弦图的完美消除序列

    MCS算法大意如下:

    给每个点定义lebel值表示有多少个已选择的点和其相连

    逆序构建完美消除序列,每次选择未选择的label值最高的点放入完美消除序列中

    同时更新label值

    如何判断一个完美消除序列是否合法?

    我们考虑逆序扫完美消除序列,假设我们扫到vi

    只需要判断vi在{vi……vn}是否是一个单纯点即可

    暴力判断显然不行

    设跟vi在{vi……vn}相连的点为vj1……vjk(按完美消除序列顺序)

    那么不难发现我们已经检查过vj1的单纯点性质了

    我们只需要考虑vj1是否和vj2……vjk相连即可

    这样判断总时间复杂度O(N+M)

    CDQ的课件中说MCS的时间复杂度为O(N+M),但是不清楚桶的做法

    所以我最多只会O(NlogN+M)的做法(用堆)

    下面是一道模板题:ZOJ  1015 O(n^2)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    
    const int maxn=1010;
    int n,m,u,v;
    int h[maxn],cnt=0;
    struct edge{
    	int to,next;
    }G[2000010];
    int pos[maxn],check[maxn];
    bool vis[maxn];
    void add(int x,int y){
    	++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;
    }
    void read(int &num){
    	num=0;char ch=getchar();
    	while(ch<'!')ch=getchar();
    	while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    }
    void Clear(){
    	memset(pos,0,sizeof(pos));
    	memset(check,0,sizeof(check));
    	memset(vis,false,sizeof(vis));
    }
    bool MCS(){
    	for(int now=n;now>=1;--now){
    		int mx=-1,mn=23333;
    		int A=0,B=0;
    		for(int i=1;i<=n;++i)if(!pos[i]&&check[i]>mx)mx=check[i],A=i;
    		pos[A]=now;
    		for(int i=h[A];i;i=G[i].next){
    			int v=G[i].to;
    			if(!pos[v])check[v]++;
    			if(pos[v]>pos[A]&&pos[v]<mn)mn=pos[v],B=v;
    		}
    		for(int i=h[B];i;i=G[i].next){
    			int v=G[i].to;
    			vis[v]=true;
    		}vis[B]=true;
    		for(int i=h[A];i;i=G[i].next){
    			int v=G[i].to;
    			if(pos[v]>pos[A]&&!vis[v])return false;
    		}
    		for(int i=h[B];i;i=G[i].next){
    			int v=G[i].to;
    			vis[v]=false;
    		}vis[B]=false;
    	}return true;
    }
    
    int main(){
    	while(scanf("%d%d",&n,&m)==2){
    		if(!n&&!m)break;
    		memset(h,0,sizeof(h));cnt=0;
    		for(int i=1;i<=m;++i){
    			read(u);read(v);
    			add(u,v);add(v,u);
    		}
    		Clear();
    		if(MCS())printf("Perfect
    
    ");
    		else printf("Imperfect
    
    ");
    	}return 0;
    }
    

    7、弦图染色问题

    直接贪心就可以了,逆序扫完美消除序列

    给每个点染能染的最小颜色,分组的答案是颜色的最大值

    时间复杂度O(N+M)

    HNOI 神奇的国度

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
     
    const int maxn=10010;
    int n,m,u,v;
    int ans;
    int h[maxn],cnt=0;
    int pos[maxn],fp[maxn];
    int check[maxn];
    int vis[maxn],c[maxn];
    struct edge{
        int to,next;
    }G[2000010];
     
    void read(int &num){
        num=0;char ch=getchar();
        while(ch<'!')ch=getchar();
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    }
    void add(int x,int y){
        ++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;
    }
    void MCS(){
        for(int now=n;now>=1;--now){
            int mx=-1,A=0;
            for(int i=1;i<=n;++i)if(!pos[i]&&check[i]>mx)mx=check[i],A=i;
            pos[A]=now;fp[now]=A;
            for(int i=h[A];i;i=G[i].next){
                int v=G[i].to;
                if(!pos[v])check[v]++;
            }
        }return;
    }
    void Get_ans(){
        for(int now=n;now>=1;--now){
            int u=fp[now];
            for(int i=h[u];i;i=G[i].next){
                int v=G[i].to;
                vis[c[v]]=now;
            }
            for(int i=1;i;++i){
                if(vis[i]!=now){c[u]=i;break;}
            }
        }
        for(int i=1;i<=n;++i)ans=max(ans,c[i]);
    }
    int main(){
        read(n);read(m);
        for(int i=1;i<=m;++i){
            read(u);read(v);
            add(u,v);add(v,u);
        }
        MCS();Get_ans();
        printf("%d
    ",ans);
        return 0;
    }
    

    8、弦图的最大独立集问题和最小团覆盖

    很容易知道最大独立集=最小团覆盖

    最大独立集就是正序扫完美消除序列,能选就选

    9、区间图

    将有重叠部分的区间之间建边,形成区间图

    可以证明区间图一定是弦图

    所以我们可以用弦图的做法求区间的各种东西

    另外值得一提的是区间图可以不用MCS求完美消除序列

    将区间按右端点从小到大排序后的结果就是完美消除序列

    cojs 简单的区间问题

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int maxn=100010;
    int n;
    struct Pos{
    	int L,R;
    }c[maxn];
    int vis[maxn];
    int col[maxn];
    
    bool cmp(const Pos &A,const Pos &B){
    	if(A.R==B.R)return A.L>B.L;
    	return A.R<B.R;
    }
    void read(int &num){
    	num=0;char ch=getchar();
    	while(ch<'!')ch=getchar();
    	while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    }
    void Solve_one(){
    	int R=-1,ans=0;
    	for(int i=1;i<=n;++i){
    		if(c[i].L>R)ans++,R=c[i].R;
    	}printf("%d
    ",ans);
    }
    void Solve_two(){
    	int ans=0;
    	for(int i=n;i>=1;--i){
    		for(int j=i+1;j<=n;++j){
    			if(c[j].L<=c[i].R)vis[col[j]]=i;
    		}
    		for(int j=1;j;j++){
    			if(vis[j]!=i){col[i]=j;break;}
    		}ans=max(ans,col[i]);
    	}printf("%d
    ",ans);
    }
    
    int main(){
    	freopen("get_pos.in","r",stdin);
    	freopen("get_pos.out","w",stdout);
    	read(n);
    	for(int i=1;i<=n;++i)read(c[i].L),read(c[i].R);
    	sort(c+1,c+n+1,cmp);
    	Solve_one();Solve_two();
    	return 0;
    }
    

    CDQ的PPT还是没看完,先总结这么多吧

  • 相关阅读:
    祝师傅新婚快乐 :)
    NetBeans IDE 6.8 里程碑 2 已经可用!
    GRETA库在VS 2005环境下的编译经验
    祝师傅新婚快乐 :)
    NetBeans 时事通讯(刊号 # 74 Sep 30, 2009)
    忆父亲
    NetBeans 时事通讯(刊号 # 74 Sep 30, 2009)
    Miss Nev great app
    订阅我不会怀孕
    数据结构排序: 两路归并排序算法 子逸 博客园
  • 原文地址:https://www.cnblogs.com/joyouth/p/5477019.html
Copyright © 2011-2022 走看看