Vijos1605 NOIP2008 提高组T4 双栈排序 BFS

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - Vijos1605


题意概括

  有1个1~n的排列,有2个栈,现在通过以下操作,使得出栈序列有序。

  操作a 当前元素入栈<S1>

  操作b 弹出S1栈顶元素

  操作c 当前元素入栈<S2>

  操作d 弹出S2栈顶元素

  如果无法使得出栈序列有序,那么输出0.

  否则输出满足条件的字典序最小的操作序列。


 

题解

  首先我们可以证明,任意时刻,任意一个栈中的元素,一定满足自底向上呈降序。

  如果不呈降序呢?

  那么会出现大的先出栈,小的后出栈的情况,所以一定不行。

  我们考虑2个元素a[i],a[j],(i<j)。

  可以得到信息:

  如果a[i]<a[j]那么a[i]先出栈

  否则 a[j]先出栈

  然后好像没有其他信息了。

  问题很严峻。

  于是我们考虑3个元素a[i],a[j],a[k](i<j<k)

  考虑所有情况。

  如果a[i]<a[j]<a[k],那么a[i],a[j]可能在同一个栈中。

  同样,

  如果a[i]<a[k]<a[j],那么a[i],a[j]可能在同一个栈中。

  如果a[j]<a[i]<a[k],那么a[i],a[j]可能在同一个栈中。

  如果a[j]<a[k]<a[i],那么a[i],a[j]可能在同一个栈中。

  如果a[k]<a[j]<a[i],那么a[i],a[j]可能在同一个栈中。(这5中情况都可以有具体操作次序,注意是“可能”)

  但是,

  如果a[k]<a[i]<a[j],那么a[i],a[j]一定不可能在同一个栈中。

  为什么?

  首先a[i]进栈。

  因为a[k]<a[i],所以在a[k]出栈之前,a[i]不能出栈。

  然而因为a[i]<a[j],如果a[i]与a[j]放在同一个栈中,那么会出现题解第一句中表述的不合法情况。

  因此a[i],a[j]一定不会在同一个栈中。

  于是我们可以先确定i,j,然后大力枚举k,按照不在同一个栈中的关系建立无向图。相邻的节点一定不会在同一个栈中。这个操作的复杂度为n^3。

  而实际上,我们可以先预处理一个后缀最小值,那么大力枚举k的时间复杂度就被压缩掉了。

  优化之后,这个操作的复杂度为n^2。

  建图之后,就是匹配栈。

  黑白染色即可。(假设栈1为白色(0),栈2为黑色(1))

  又由于题目要字典序最小的,所以我们尽量给编号小的节点染成白色就可以了。

  于是我们大力跑一遍广搜。

  当然染色的过程中会出现相邻节点颜色相同的情况,那么就是无解,直接输出0。

  广搜完了之后,每一个数字安排的栈位置都已经弄好了。

  然后就是模拟了。

  模拟的时候,还是要注意字典序最小的问题。

  注意按照之前匹配的一定有解的。

  模拟具体过程:

  我们弄一个计数器cnt,表示当前出栈到了哪一个数字。

  对于每次压入元素前,如果栈1的栈顶元素是cnt+1,那么要先将栈1出栈。

  因为,如果当前元素匹配的是栈2,那么自然就是栈1出栈优先。

  如果是栈1,那么元素值一定会比cnt+1要大,不满足最前面的那一条。

  然后,注意对于同一个栈,入栈的优先级一定比出栈高。

  所以,我们尽量提前入栈。

  但是入栈是有条件的,要维持序列降序。

  那么就要先出栈,直到满足降序为止。

  出栈也是有规矩的。要满足cnt+1,所以是两个栈乱序出栈的。

  我的程序貌似有点小问题,但是数据水,过去了……

  具体:

  如果匹配栈2,那么出栈操作之后,满足栈2降序之后,其实有字典序更小的方案。

  因为栈2入栈,是c,而栈1出栈是b,所以栈1先出栈是赚的。但是我忘记判这个情况了。

  然后居然……

  至此,rzO膜拜大佬出据人Orz


 

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <queue>
using namespace std;
const int N=1000+5,Inf=100000;
struct Stack{
    int v[N],t;
    void clear(){
        t=0;
    }
    void push(int x){
        v[++t]=x;
    }
    void pop(){
        t--;
    }
    bool empty(){
        return t==0;
    }
    int top(){
        if (t==0)
            return Inf;
        return v[t];
    }
}s1,s2;
int n,a[N],Min[N],match[N],vis[N],cnt;
bool g[N][N];
queue <int> q;
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    Min[n]=10000;
    for (int i=n-1;i>=1;i--)
        Min[i]=min(Min[i+1],a[i+1]);
    memset(g,0,sizeof g);
    for (int i=1;i<=n;i++)
        for (int j=i+1;j<=n;j++)
            if (a[i]<a[j]&&Min[j]<a[i])
                g[i][j]=g[j][i]=1;
    memset(vis,0,sizeof vis);
    for (int i=1;i<=n;i++){
        if (vis[i])
            continue;
        while (!q.empty())
            q.pop();
        vis[i]=1,match[i]=0;
        q.push(i);
        while (!q.empty()){
            int x=q.front();
            q.pop();
            for (int j=1;j<=n;j++){
                if (!g[x][j])
                    continue;
                if (!vis[j]){
                    match[j]=match[x]^1;
                    q.push(j);
                    vis[j]=1;
                }
                else if (match[j]==match[x]){
                    printf("0");
                    fclose(stdin);fclose(stdout);
                    return 0;
                }
            }
        }
    }
    cnt=0;
    s1.clear(),s2.clear();
    for (int i=1;i<=n;i++){
        while (s1.top()==cnt+1){
            printf("b ");
            s1.pop();
            cnt++;
        }
        if (match[i]==0){
            while (a[i]>s1.top()&&(s1.top()==cnt+1||s2.top()==cnt+1))
                if (s1.top()==cnt+1){
                    printf("b ");
                    s1.pop();
                    cnt++;
                }
                else {
                    printf("d ");
                    s2.pop();
                    cnt++;
                }
            s1.push(a[i]);
            printf("a ");
        }
        if (match[i]==1){
            while (a[i]>s2.top()&&(s1.top()==cnt+1||s2.top()==cnt+1))
                if (s1.top()==cnt+1){
                    printf("b ");
                    s1.pop();
                    cnt++;
                }
                else {
                    printf("d ");
                    s2.pop();
                    cnt++;
                }
            s2.push(a[i]);
            printf("c ");
        }
    }
    while (!s1.empty()||!s2.empty())
        if (s1.top()<s2.top()){
            printf("b ");
            s1.pop();
        }
        else {
            printf("d ");
            s2.pop();
        }
    return 0;
}

  

posted @   zzd233  阅读(362)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 手把手教你更优雅的享受 DeepSeek
· AI工具推荐:领先的开源 AI 代码助手——Continue
· 探秘Transformer系列之(2)---总体架构
· V-Control:一个基于 .NET MAUI 的开箱即用的UI组件库
· 乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现

点击右上角即可分享
微信分享提示