【Luogu】P1155双栈排序(二分图)

题目链接在此

   此题一开始写了个深搜,过了30%的数据,也就是n<=10的那一段。。。。

   然后看了题解发现这是个二分图的判断。

   我们先举例子找到不能放进一个栈里的规律。设有数列【2,3,1,4】

   容易模拟得到这个数列单栈是搞不出来的。为什么搞不出来呢?

   如果输入的序列是单调递减的,自然一个栈可以搞定。直接全部压栈再全部弹栈就可以了。

   如果输入的序列不是单调递减,一个栈也有可能搞定。但是像我们举的这个例子,你压3的时候必须把2压在底下,那怎么先出2后出3呢?

   继续模拟能够发现规律:若i、j不能单栈,当且仅当存在k使得i<j<k且que[k]<que[i]<que[j]

   于是就可以把不能单栈的元素连一条无向边,剩下的工作就是判断这张图是否是二分图了。

   二分图怎么判断呢?由于这张图中相连点只能属于不同的两个集合,要么A要么B,所以我们可以对点染色。比如A连着B,B连着C,我们就可以先给A染成-1,然后给B染成1,然后给C染成-1.如果发现染色有冲突那就连不成二分图。

   随后模拟即可

   代码如下

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
int INF=0x7fffffff;
inline long long min(long long a,long long b){    return a<b?a:b;    }
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to;
}edge[1000000];
int head[1000000],num;
inline void add(int from,int to){
    edge[++num]=(Edge){head[from],to};
    head[from]=num;
}

int f[10000];
int que[10000];
int val[10000];
int stackA[10000],topA;
int stackB[10000],topB;

bool dfs(int x,int c){
    val[x]=c;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(val[to]&&val[to]==c)    return 0;
        else if(!val[to]){
            val[to]=-c;
            if(!dfs(to,-c))    return 0;
        }
    }
    return 1;
}

int main(){
    int n=read();
    for(int i=1;i<=n;++i)    que[i]=read();
    f[n+1]=INF;
    for(int i=n;i>=1;--i)    f[i]=min(f[i+1],que[i]);
    for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j)
            if(f[j+1]<que[i]&&que[i]<que[j]){
                add(i,j);
                add(j,i);
            }
    for(int i=1;i<=n;++i){
        if(!val[i]){
            bool flag=dfs(i,1);
            if(!flag){
                printf("%d",0);
                return 0;
            }
        }
    }
    int cnt=1;
    for(int i=1;i<=n;++i){
        if(val[i]==1){
            printf("a ");
            stackA[++topA]=que[i];
        }
        else{
            printf("c ");
            stackB[++topB]=que[i];
        }
        while((topA&&stackA[topA]==cnt)||(topB&&stackB[topB]==cnt)){
            if(topA&&stackA[topA]==cnt){
                printf("b ");
                topA--;
            }
            else{
                printf("d ");
                topB--;
            }
            cnt++;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/7467388.html