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还是没看完,先总结这么多吧

  • 相关阅读:
    LeetCode 121. Best Time to Buy and Sell Stock
    LeetCode 221. Maximal Square
    LeetCode 152. Maximum Product Subarray
    LeetCode 53. Maximum Subarray
    LeetCode 91. Decode Ways
    LeetCode 64. Minimum Path Sum
    LeetCode 264. Ugly Number II
    LeetCode 263. Ugly Number
    LeetCode 50. Pow(x, n)
    LeetCode 279. Perfect Squares
  • 原文地址:https://www.cnblogs.com/joyouth/p/5477019.html
Copyright © 2011-2022 走看看