• noip 2008 双栈排序


    题目大意: 给定n和一串数字,这串数字是一个1~n的排列。现在要用两个栈给这些数字排序。首先先判断是否有解,有解的话再输出字典序最小的方案:

    入栈1,输出a,出栈1,输出b

    入栈2,输出c,出栈2,输出d

    分析:

    首先必然要先考虑是否有解。对于没有解的情况,必然是当到了某一个数x0时,栈1,栈2队首元素都不能弹出,并且x0要比栈1、2的队首元素都要大,这时就不能排序了。

    所以考虑什么时候A、B不能在同一个栈中的情况:

    当且仅当,A<B,并且存在C,使得A>C.并满足A位置在B前面,B位置在C前面。就是说,由于C的存在,A不能pop掉,但是B放进去,A就永远pop不了了。

    这样就可以找到所有不能和x0在同一个栈里的所有位置上的数了。

    判断无解时,将所有上述的A和B之间连一条无向边,用二分图染色或者带偏移量的并查集都可以。

    输出时,因为要字典序最小,所以第一个元素必然要放进栈1,这样可以预处理出来所有数要进入哪一个栈。能进栈1的都进栈1.

    然后模拟实现,每次先要判断是否可以pop掉栈顶元素,然后按照之前的预处理的方案放进数就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1010;
    int a[N],la[N],co[N];
    int n;
    int head[N];
    int cnt=1;
    bool flag=0;
    
    int sta[3][N];//记录栈1、栈2
    int top[3];//记录栈顶
    int go[N];//这个位置上的数要去哪一个栈
    int has;//已经出栈到几号
    
    struct node{
        int to,nxt;
    }bian[2*N];
    void add(int x,int y)
    {
        bian[++cnt].nxt=head[x];
        bian[cnt].to=y;
        head[x]=cnt;
    }//建边
    void dfs1(int x,int fa,int se)//1 black 2 white
    {
        if(flag) return;
        co[x]=se;
        for(int i=head[x];i;i=bian[i].nxt)
        {
            int y=bian[i].to;
            if(y==fa) continue;
            if(co[y])
            {
                if(co[y]==co[x])
                {
                    flag=1;return;
                }
            }
            else{
                dfs1(y,x,3-se);
            }
        }
    }//二分图染色判断
    void dfs2(int x,int se)
    {
        go[x]=se;
        for(int i=head[x];i;i=bian[i].nxt)
        {
            int y=bian[i].to;
            if(!go[y])
            {
                dfs2(y,3-se);
            }
        }
    }//预处理该去的栈(其实也可以在二分图染色时处理出来,就省了这步)
    void check(int now)
    {
        bool f=0;
        while(top[now]&&has+1==sta[now][top[now]])
        {
            f=1;
            printf("%c ",now==1?'b':'d');
            has++;
            top[now]--;
        }
        if(f)//成功pop才找另一个
         check(3-now);
    }
    //检查能否pop
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
         for(int j=n;j>=i+1;j--)
         {
            if(a[i]>a[j]) 
            {la[i]=j;break;}
         }//找到A的最后面一个C的位置。
        for(int i=1;i<=n;i++)
         for(int j=i+1;j<=la[i];j++)
         {
            if(a[i]<a[j])
            {
                add(i,j);
                add(j,i);
             }
         }//A到C之间所有的B都要和A建边
        for(int i=1;i<=n;i++)
        {
            if(flag==1) break;
            if(!co[i]) dfs1(i,0,1);
        }
        if(flag) {
            printf("0");
            return 0;
        }//判断
    
        go[1]=1;
        for(int x=1;x<=n;x++)
        {
         if(!go[x]) go[x]=1,dfs2(x,1);
        }
        for(int i=1;i<=n;i++)
        {
            check(1);
            check(2);
            sta[go[i]][++top[go[i]]]=a[i];
            printf("%c ",go[i]==1?'a':'c');
        }
        check(1);
        check(2);//最后也要判断,输出完。
        return 0;
    }
    
    她透过我的血,看到了另一抹殷红
  • 相关阅读:
    单片机多功能调试助手
    《划时代51单片机C语言全新教程》第十九章 网络通信 概览
    《划时代51单片机C语言全新教程》第十五章 按键计数器 概览
    《划时代51单片机C语言全新教程》第十七章 频率计 概览
    前后台程序框架实例2
    《划时代51单片机C语言全新教程》第二十一章 深入编程 概览
    《划时代51单片机C语言全新教程》第二十二章 界面开发 概览
    《划时代51单片机C语言全新教程》第十八章 USB通信 概览
    《划时代51单片机C语言全新教程》第二十章 深入接口 概览
    《划时代51单片机C语言全新教程》第十六章 交通灯 概览
  • 原文地址:https://www.cnblogs.com/zhangbeini/p/13771235.html
Copyright © 2020-2023  润新知