双栈排序(二分图染色+模拟)

Posted greengenius

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双栈排序(二分图染色+模拟)相关的知识,希望对你有一定的参考价值。

题目链接  https://www.luogu.org/problemnew/show/P1155

技术分享图片

技术分享图片

技术分享图片

技术分享图片

 

 技术分享图片

一开始我还以为能直接模拟=-=,太天真了...写了好久对了3个点...看了题解之后恍然大悟,先二分图匹配一下确定每个点在哪个栈里头再模拟会轻松很多。可怎么建边呢?

我们先从单栈排序开始:

可以的出的是,对于i,j,若存在k使得i<j<k,且A[k]<A[i]<A[j]的时候,是一定不能单栈排序的

就像3 4 1这样的数,因为要保证小的先出来,

我们可以在这样的i,j间建边,用f[i]存i之后最小的数,这样就可以把复杂度降到n的平方

之后就可以二分图染色了=-=,染色时要注意1-n不一定时联通的,所以要for一遍把所有都染掉

然后就是模拟了=-=字典序有点恶心,但只要时刻保证先出来在进去,先考虑s1,再考虑s2就可以了

代码:

#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cstring>
using namespace std;
const int N=1010;
int f[N],A[N];
struct node{
    int nu,ne;
}edge[N*N];
int tot,n;
int col[N],head[N],belong[N];
char ans[N*2];
bool vis[N];
void add(int a,int b)
{
    edge[++tot].nu=b;
    edge[tot].ne=head[a];
    head[a]=tot;
}
bool bfs(int st)
{
    queue<int>q;
    q.push(st);
    col[st]=1;
    vis[st]=true;
    while(!q.empty())
    {
        int a=q.front();
        q.pop();
        for(int i=head[a];i!=-1;i=edge[i].ne)
        {
            int k=edge[i].nu;
            if(col[k]==col[a])return false;
            if(vis[k]) continue;
            vis[k]=true;
            col[k]=col[a]==1?2:1;
            q.push(k); 
        }
    }
    return true;
}
int main()
{
    memset(head,-1,sizeof(head));
    stack<int>s1,s2;
    int bj=1,cnt=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&A[i]);
    memset(f,0x3f,sizeof(f));
    A[n+1]=1e7;
    for(int i=n;i>=1;i--)
        f[i]=min(f[i+1],A[i]); 
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(A[j]>A[i]&&A[i]>f[j+1])
                add(A[i],A[j]),add(A[j],A[i]);
    for(int i=1;i<=n;i++)
        if(!col[A[i]])
            if(!bfs(A[i]))
                return printf("0
"),0;
    for(int i=1;i<=n;i++)
    {
        if(col[A[i]]==1)
            belong[A[i]]=1;
        if(col[A[i]]==2)
            belong[A[i]]=2;
    }
    for(int i=1;i<=n;i++)
    {
        int a=belong[A[i]];
        while(!s1.empty()&&s1.top()==bj)
        {
            bj++;
            s1.pop();
            ans[++cnt]=b;
        }
        while(!s2.empty()&&s2.top()==bj)
        {
            bj++;
            s2.pop();
            ans[++cnt]=d;
        }
        if(a==1)
        {
            s1.push(A[i]);
            ans[++cnt]=a;
        }
        if(a==2)
        {
            s2.push(A[i]);
            ans[++cnt]=c;
        }
    }
    while(!s1.empty()&&!s2.empty())
    {
        if(s1.top()<s2.top())
        {
            s1.pop();
            ans[++cnt]=b;
        }
        else
        {
            s2.pop();
            ans[++cnt]=d;
        }
    }
    while(!s1.empty())s1.pop(),ans[++cnt]=b;
    while(!s2.empty())s2.pop(),ans[++cnt]=d;
    for(int i=1;i<=cnt;i++)
        printf("%c ",ans[i]);
    return 0;
}

 

以上是关于双栈排序(二分图染色+模拟)的主要内容,如果未能解决你的问题,请参考以下文章

双栈排序 2008年NOIP全国联赛提高组(二分图染色)

双栈排序

[LuoguP1155]双栈排序_二分图_bfs

codevs1170 双栈排序

AC日记——双栈排序 洛谷 P1155

双栈排序(二分图