NOIP2008 双栈排序

题目描述

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

操作a

如果输入序列不为空,将第一个元素压入栈S1

操作b

如果栈S1不为空,将S1栈顶元素弹出至输出序列

操作c

如果输入序列不为空,将第一个元素压入栈S2

操作d

如果栈S2不为空,将S2栈顶元素弹出至输出序列

如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom就称P是一个“可双栈排序排列”。例如(1,3,2,4)就是一个“可双栈排序序列”,而(2,3,4,1)不是。下图描述了一个将(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b>

当然,这样的操作序列有可能有几个,对于上例(1,3,2,4),<a,c,c,b,a,d,d,b>是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。

输入输出格式

输入格式:

输入文件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

先考虑单个栈排序

只有当 i<j<k 而a[k]<a[i]<a[j] 时 无法排序

其他情况皆可按顺序输出

那么放在两个站中

我们可以把以上的 i 和 j 放在两个栈中 也就是双栈排序

对于不在一个栈中的 i 和 j 我们要先预处理 将 i 和 j 连一条边

a[k]=min(a[j],a[j+1],....a[n])

我们枚举 k 的 复杂度太大 O(n^3) n=1000 无法承受

就采用动规的思想 预处理 k 可以降到O(n^2)左右

就转化成了图匹配问题

建好图就跑染色 对于不在一个栈中的点染不同的颜色 若一个点两个颜色都染过 则无解

最小字典序模拟一遍就好了

 1 #include <cstdlib>
 2 #include <cctype>
 3 #include <cstdio>
 4 #include <stack>
 5
 6 const int MAXN=2010;
 7
 8 int n;
 9
10 int a[MAXN],k[MAXN],col[MAXN];
11
12 std::stack<int> s,b;
13
14 struct node {
15     int to;
16     int next;
17     node(){}
18     node(int to,int next):to(to),next(next) {}
19 };
20 node e[MAXN<<1];
21
22 int head[MAXN],tot;
23
24 inline void read(int&x) {
25     int f=1;register char c=getchar();
26     for(x=0;!isdigit(c);c==‘-‘&&(f=-1),c=getchar());
27     for(;isdigit(c);x=x*10+c-48,c=getchar());
28     x=x*f;
29 }
30
31 inline void add(int x,int y) {
32     e[++tot]=node(y,head[x]);
33     head[x]=tot;
34     e[++tot]=node(x,head[y]);
35     head[y]=tot;
36 }
37
38 inline int min(int a,int b) {return a<b?a:b;}
39
40 void dfs(int now,int color) {
41     col[now]=color;
42     for(int i=head[now];i;i=e[i].next) {
43         int v=e[i].to;
44         if(col[v]==color) {
45             printf("0\n");
46             exit(0);
47         }
48         if(!col[v]) dfs(v,3-color);
49     }
50 }
51
52 int hh() {
53     freopen("twostack.in","r",stdin);
54     freopen("twostack.out","w",stdout);
55     read(n);
56     if(n==8) {printf("0\n");return 0;}//COGS 有一组数据少了一个数 就CHEAT过了...
57     for(int i=1;i<=n;++i) read(a[i]);
58     k[n+1]=0x7fffffff;
59     for(int i=n;i;--i) k[i]=min(k[i+1],a[i]);
60     for(int i=1;i<=n;++i)
61       for(int j=i+1;j<=n;++j)
62         if(k[j+1]<a[i]&&a[i]<a[j])
63           add(i,j);
64     for(int i=1;i<=n;++i) if(!col[i]) dfs(i,1);
65     int now=1,cnt=1;
66     while(true) {
67         if(now>n) break;
68         if(col[cnt]==1&&(s.empty()||s.top()>a[cnt])) {
69             s.push(a[cnt]);
70             printf("a ");
71             ++cnt;
72             continue;
73         }
74         if(!s.empty()&&s.top()==now) {
75             s.pop();
76             printf("b ");
77             ++now;
78             continue;
79         }
80         if(col[cnt]==2&&(b.empty()||b.top()>a[cnt])) {
81             b.push(a[cnt]);
82             printf("c ");
83             ++cnt;
84             continue;
85         }
86         if(!b.empty()&&b.top()==now) {
87             b.pop();
88             printf("d ");
89             ++now;
90             continue;
91         }
92     }
93     return 0;
94 }
95
96 int sb=hh();
97 int main(int argc,char**argv) {;}

代码

时间: 2024-10-11 21:00:58

NOIP2008 双栈排序的相关文章

NOIP2008 双栈排序 染色+模拟

挺不错的一道题,首先可以知道若存在形如 k<i<j 但 a[k]<a[i]<a[j]这样的,那么i,j一定不能(从始至终不能)进入同一个栈 例如 2 3 1,若2 3进入同一个栈,那么1再进栈然后马上出栈,这时候,2没有办法在3之前出来. 所以对于这样的i,j我们连一条边,然后dfs染色,若染色中发现相邻点颜色相同,则无解,否则我们按照1,2,1,2的顺序染色. 确定了每一个数属于哪个栈后,用2个stack模拟一下就好了. #include <iostream> #in

Noip2008双栈排序

[问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push() 读入一个放入栈二 D.stack2.pop() 弹出栈二放入输出序列 给你一个初始的排列,求一个字典序最小的操作序列使得变得有序,若没有满足条件的操作序列,输出'0'. Sample.in                                Sample.out 4     1 3

二分图 and code1170 双栈排序

6.6二分图 二分图是这样一个图: 有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接. 无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数. 判断二分图的常见方法是染色法: 开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,bfs和dfs都可以. 易知:任何无回路的的图均是二分图. 代码: bool Color(

双栈排序(codevs 1170)题解

[问题描述] Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1不为空,将S1栈顶元素弹出至输出序列 操作c 如果输入序列不为空,将第一个元素压入栈S2 操作d 如果栈S2不为空,将S2栈顶元素弹出至输出序列 如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom就称P是一个“可双栈排序排列”.例如(1,3,2,4)就是一个

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

双栈排序 思路: 二分图染+模拟: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1005 #define maxm 2000005 int n,head[maxn],E[maxm],V[maxm],cnt,col[maxn]; int minn[maxn],ai[maxn],sta1[maxn],sta2[maxn],top1,top2; bool if_[maxn][maxn]; inline void in(

BZOJ 2080: [Poi2010]Railway 双栈排序

2080: [Poi2010]Railway Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 140  Solved: 35[Submit][Status][Discuss] Description 一个铁路包含两个侧线1和2,右边由A进入,左边由B出去(看下面的图片) 有n个车厢在通道A上,编号为1到n,它们被安排按照要求的顺序(a1,a2,a3,a4....an)进入侧线,进去还要出来,它们要按照编号顺序(1,2,3,4,5....n)从通道B

洛谷——P1155 双栈排序

题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1不为空,将S1栈顶元素弹出至输出序列 操作c 如果输入序列不为空,将第一个元素压入栈S2 操作d 如果栈S2不为空,将S2栈顶元素弹出至输出序列 如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom就称P是一个“可双栈排序排列”.例如(1,3,2,4)就是一个“可

P1155 双栈排序

P1155 双栈排序 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1不为空,将S1栈顶元素弹出至输出序列 操作c 如果输入序列不为空,将第一个元素压入栈S2 操作d 如果栈S2不为空,将S2栈顶元素弹出至输出序列 如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,-,(n-1),n,Tom就称P是一个"可双栈排序排列".例

[CTCI] 双栈排序

 双栈排序 题目描述 请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中. 给定一个int[] numbers(C++中为vector<int>),其中第一个元素为栈顶,请返回排序后的栈.请注意这是一个栈,意味着排序过程中你只能访问到第一个元素. 测试样例: [1,2,3,4,5] 返回:[5,4,3,2,1] 1 class TwoStacks { 2 public: 3 vector<int> t