luoguP1155 双栈排序

题目描述

Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。

操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列

输入输出格式

输入格式:
输入文件twostack.in的第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。

输出格式:
输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。

输入输出样例

输入样例#1:
【输入样例1】
4
1 3 2 4

【输入样例2】
4
2 3 4 1

【输入样例3】
3
2 3 1

输出样例#1:
【输出样例1】
a b a a b b a b

【输出样例2】
0

【输出样例3】
a c a b b d

说明
30%的数据满足: n<=10
50%的数据满足: n<=50
100%的数据满足: n<=1000

分析:
第一眼看过去,很简单啊,模拟一下就好了
只要遵循:
在栈里的元素一定是单调递减的
栈里相邻元素相差的越少越好,
优先选择第一个栈
实测:40分
这完全就是钻制度的空子。。。

好吧,说正经的

考虑a[i],a[j]两个元素不能进入同一个栈的条件.
注意,这里所说的”a[i],a[j]两个元素不能进入同一个栈“,
是自始至终不能进入一个栈,
即如果有解,那么a[i],a[j]一定进入过的栈不同.

条件:存在k使得i < j < k且a[k] < a[i] < a[j]
进栈顺序i->j->k
栈中的元素一定是单调减的
如果ta们在一个栈中,那么进栈顺序是j->i->k,与原命题矛盾

那知道了这个有什么用呢
我们可以知道元素两两能不能在一起,
如果i和j不能在一起,j和k不能在一起,i和k不能在一起,那原序列无解

我们把不能在一起的一对点之间连边
(突然觉得这蜜汁像关押罪犯,当有冲突时,就把边两端的点分配到不同的集合中去)
之后遍历一遍进行01染色
这样我们知道了进栈的状况,就可以直接模拟输出了
(直接上40分的骗分)

tip

按理说在处理冲突点对的时候是O(n^3)的复杂度,对于1000太大了,大神说要用dp优化一下,但是luogu数据实在是太耿直了,打的三方暴力就这样A了

简单说一下dp优化,
因为我们只要找到一个k满足就判定是冲突点对,
所以设f[i]表示i-n中的最小值
如果最小值都满足不了那就不可能了
这样可以把k的循环降到O(1)

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>

using namespace std;

const int N=1010;
int n,a[N];
char s[N];
struct node{
    int x,y,nxt;
};
node way[N<<1];
int st[N],tot=0,co[N],st1[N],st2[N];

void add(int u,int w)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
    tot++;
    way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot;
}

void doit()
{
    int i,j;
    memset(co,-1,sizeof(co));
    queue<int> q;
    q.push(way[1].x);
    co[way[1].x]=0;
    while (!q.empty())   //染色 
    {
        int r=q.front();
        q.pop();
        for (i=st[r];i;i=way[i].nxt)
        {
            if (co[way[i].y]==-1) 
            {
                co[way[i].y]=(co[r]==0 ? 1:0);
                q.push(way[i].y);
            }
            else if (co[way[i].y]==co[r])
            {
                printf("0
");
                return;
            }
        }
    }
    int t=-1,t1=0,t2=0,k=1;
    for (i=1;i<=n;i++)
    {
        if (a[k]==i)
        {
            printf("a b ");k++;
            continue;
        }
        if (st1[t1]==i)
        {
            printf("b "); t1--; continue;
        }
        if (st2[t2]==i)
        {
            printf("d "); t2--; continue;
        }
        while (a[k]!=i)
        {
            if (co[k]==0||co[k]==-1)
               printf("a "),st1[++t1]=a[k];
            else printf("c "),st2[++t2]=a[k];
            k++;
        }
        printf("a b ");k++;
    }
    return; 
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<n-1;i++)  //i<j<k  a[k]>a[i]>a[j]
        for (int j=i+1;j<n;j++)
        {           
            if (a[i]<a[j])
            for (int k=j+1;k<=n;k++)
                if (a[k]<a[i])
                {
                    add(i,j);break;
                } 
        }
    doit();
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673443.html