zoukankan      html  css  js  c++  java
  • 二分图 and code1170 双栈排序

    6.6二分图

    二分图是这样一个图: 有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接。

    无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。

    判断二分图的常见方法是染色法: 开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,bfs和dfs都可以。

    易知:任何无回路的的图均是二分图。

    代码: 

    bool Color(int u)  

    {  

        for(int i=head[u]; ~i; i=edge[i].next)  

        {  

            int v = edge[i].to;  

            if(!col[v])  

            {  

                col[v] = !col[u];  

                if(!Color(v)) return false;  

            }  

            else if(col[v] == col[u])  

                return false;  

        }  

        return true;  

    }  

    Codevs1170 双栈排序NOIP2008

    题目分析:

    分析条件,我们把问题抽象为数学模型。设输入序列为S,考虑S[i],S[j]两个元素不能进入同一个栈的条件.注意,这里所说的"S[i],S[j]两个元素不能进入同一个栈",不是说仅仅不能同时在一个栈中,而是自始至终不能进入一个栈,即如果有解,那么S[i],S[j]一定进入过的栈不同.

    结论P: S[i],S[j]两个元素不能进入同一个栈 <=> 存在k,满足i<j<k,使得S[k]<S[i]<S[j]. 证明略过,请参考sqybi.尝试后可以发现结论P是正确的.

    把每个元素按照输入序列中的顺序编号,看作一个图中的每个顶点.这时,我们对所有的(i,j)满足i<j,判断是否满足结论P,即S[i],S[j]两个元素能否进入同一个栈.如果满足P,则在i,j之间连接一条边.

    我们对图染色,由于只有两个栈,我们得到的图必须是二分图才能满足条件.由于要求字典序最小,即尽量要进入栈1,我们按编号递增的顺序从每个未染色的顶点开始染色,相邻的顶点染上不同的色,如果发生冲突,则是无解的.否则我们可以得到每个顶点颜色,即应该进入的栈.

    接下来就是输出序列了,知道了每个元素的决策,直接模拟了.

    在判断数对(i,j)是否满足P时,枚举检查是否存在k的时间复杂度是O(n),则总的时间复杂度是O(n^3),对于n=1000是太大了.这原因在于过多得枚举了k,我们可以用动态规划把枚举k变为O(1)的算法.

    设F[i]为Min{S[i],S[i+1],S[i+2]..S[n-1],S[n]},状态转移方程为F[i]=Min{ S[i] , F[i+1] }.边界为F[N+1]=极大的值.

    判断数对(i,j)是否满足P,只需判断(S[i]<S[j] 并且 F[j+1]<S[i])即可.时间复杂度为O(n^2).

    多亏有题解,不然根本想不出来那个结论P啊...

    模拟也是个问题:

    知道了每个点的color(cc),入栈很容易。问题是什么时候出栈。

    设a为当前需要出栈的元素,b为a+1

    当s1的栈顶是a时,立刻出栈。因为出s1的优先级是2,只有入s1比它高,但那样就把应该出的元素压住了,显然不行。所以直接出就能保证字典序最小。

    当s2的栈顶是a时,麻烦来了。因为出s2的优先级比入s1低,所以如果可能应当先入s1,把该出的元素放在s2不管它,直到迫不得已必须出的时候。

      s2出栈的情况:s2的栈顶是a时,cc[i+1]==2 || (cc[i+1]==1&&!s1.empty()&&s1.top()==b) || s1.empty()

    注意模拟之前先cc[n+1]=2,保证入栈全部完成时s2不再受入栈限制(cc[i+1]==2)

    详见代码:

    #include<iostream>
    #include<stack>
    using namespace std;
    const int Size=1005;
    
    int n,data[Size];
    int f[Size];
    int cc[Size];
    bool flag=true;
    int a=1,b=2;
    stack<int> s1,s2;
    //edge
    struct E{
        int to;
        E *next;
    }*head[Size];
    void add(int a,int b){
        E *p=new E;
        p->to=b; p->next=head[a];
        head[a]=p;
    }
    
    void color(int u){
        for(E* i=head[u]; i!=NULL; i=i->next){  
            int v = i->to;  
            if(!cc[v]){  
                cc[v] = cc[u]==1?2:1;  
                color(v);
                if(!flag)return;  
            }  
            else if(cc[v] == cc[u]){
                flag=false;
                return;
            }
        }  
    }
    
    void out(int i){
        bool ok=true;
        while(ok){
            ok=false;
            if(!s1.empty()&&s1.top()==a){
                s1.pop(); cout<<"b "; a++;b++; ok=true;
            }
            if(!s2.empty()&&s2.top()==a){
                if(cc[i+1]==2||(cc[i+1]==1&&!s1.empty()&&s1.top()==b)||s1.empty()){
                    s2.pop(); cout<<"d "; a++;b++; ok=true;
                }
            }
        }
    }
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)head[i]=NULL;
        for(int i=1;i<=n;i++){
            cin>>data[i];
        }
        f[n+1]=0x3f3f3f3f;
        for(int i=n;i>=1;i--){
            f[i]=min(data[i],f[i+1]);
        }
        
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(data[i]<data[j]&&f[j+1]<data[i]){
                    add(i,j); add(j,i);
                }
            }
        }
        
        for(int i=1;i<=n;i++){
            if(cc[i]==0){
                cc[i]=1;
                color(i);
                if(!flag)break;
            }
        }
        
        cc[n+1]=2;
        if(flag){
            for(int i=1;i<=n;i++){
                if(cc[i]==1)s1.push(data[i]),cout<<"a ";
                else s2.push(data[i]),cout<<"c ";
                out(i);
            }
        }
        else cout<<0;
        
        return 0;
    } 
  • 相关阅读:
    Docker----mysql数据持久化
    Docker-----容器数据卷
    Docker-----制造自己的镜像
    Docker----常用命令(镜像和容器的常用命令)
    Docker----阿里云镜像加速
    Docker概述
    com.aliyuncs.exceptions.ClientException: InvalidVersion : Specified parameter Version is not valid.
    夜神模拟器的使用踩坑--adb devices无法连接设备
    python利用smtplib模块发送邮件
    appium环境安装说明
  • 原文地址:https://www.cnblogs.com/FuTaimeng/p/5636129.html
Copyright © 2011-2022 走看看