洛谷P1155 [NOIP2008 提高组] 双栈排序

题意

有两个栈,四个操作

a.把数据压入栈1

b.弹出1中栈顶数据

c.把数据压入2

d.弹出2中栈顶数据

要通过一系列操作,将读入的n个1~n的不重复的数据升序排列,如果无法排列则输出0,否则输出字典序最小的操作顺序。

思路

本题分为两个步骤:1.判断能否成功排序;2.输出最小字典序的操作。

假定只有一个栈,那么什么时候会出现无法排序的情况呢?

手推几组数据,便可以发现,当i<j<k时,a[k]<a[i]<a[j]便会出现矛盾,此时i和j必定要有一个去第二个栈中

有两个栈,两个数据不能在同一个栈中,我们会想到什么?

二分图嘛

所以我们在i,j上连一条边,我们先预处理出所有的连边:

    minn[n+1]=n+1;
    for(int i=n;i>=1;i--) minn[i]=min(minn[i+1],a[i]);
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            if(minn[j+1]<a[i] && a[i]<a[j]){
                add(i,j);
                add(j,i);
            }

其中,minn数组表示在该点后所有数据中的最小值,也就是上面的k

然后就通过染色的方法,判断该数据能不能排序,如果染色过程中产生了冲突,也就是说一个数据既要在栈1又要在栈2中,那么肯定无法排序,输出0即可

之后就是进行操作了,因为我们要求字典序最小,所以肯定尽量入栈1,出的时候也尽量先出栈1

而如果要求能升序排列,那么每一个栈中的数据必须是降序排列的,而如果突然比前面大了,我们就要把前面比它小的都先输出来

输出的时候我们记录现在要输出的数,如果在栈1顶就操作b,否则必然在栈2顶,就操作d

输出完后把该点入到对应的栈。

最后把所有的数据按照顺序输出即可~

void add(int u,int v){
    tail++;
    nxt[tail]=head[u];
    head[u]=tail;
    to[tail]=v;
}

void dfs(int u,int cl){
    if(!flag) return;
    if(vis[u]){
        if(color[u]!=cl) flag=0;
        return;    
    }
    vis[u]=1; 
    color[u]=cl;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        dfs(v,1-cl);
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    minn[n+1]=n+1;
    for(int i=n;i>=1;i--) minn[i]=min(minn[i+1],a[i]);
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            if(minn[j+1]<a[i] && a[i]<a[j]){
                add(i,j);
                add(j,i);
            }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            flag=1;
            dfs(i,0); 
        }
        if(!flag) break;
    }
    if(!flag){
        printf("0\n");
        return 0;
    }
    else{
        int now=1;
        set1[0]=set2[0]=n+1;
        for(int i=1;i<=n;i++)
            if(!color[i]){
                while(a[i]>set1[top1] && now<=n)
                    if(set1[top1]==now){
                        printf("b ");
                        now++;
                        top1--;
                    }
                    else{
                        printf("d ");
                        now++;
                        top2--;
                    }
                printf("a ");
                set1[++top1]=a[i];
            }
            else{
                while(set1[top1]==now && now<=n){
                    printf("b ");
                    now++;
                    top1--;
                }
                while((a[i]>set2[top2] || set1[top1]==now) && now<=n)
                    if(set1[top1]==now){
                        printf("b ");
                        now++;
                        top1--;
                    }
                    else{
                        printf("d ");
                        now++;
                        top2--;
                    }
                printf("c ");
                set2[++top2]=a[i];
            }
        while(now<=n)
            if(set1[top1]==now){
                printf("b ");
                now++;
                top1--;
            }
            else{
                printf("d ");
                now++;
                top2--;
            }
    }
View Code

 

posted @ 2021-08-11 10:43  鹤翅拥三边  阅读(188)  评论(0)    收藏  举报