Problem
【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>
![](https://cdn.luogu.org/upload/pic/51.png)
当然,这样的操作序列有可能有几个,对于上例(1,3,2,4),<a,c,c,b,a,d,d,b>是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。
输入输出格式
输入格式:
输入文件twostack.in的第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1∼n的排列。
输出格式:
输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
输入输出样例
输入样例#1
输出样例#1
输入样例#2
输出样例#2
输入样例#3
输出样例#3
说明
30%的数据满足: n≤10
50%的数据满足: n≤50
100%的数据满足: n≤1000
标签:二分图染色
Solution
一道很有意思的联赛题。
对于任意两数i,j,k,若有i<j<k,ak<ai<aj,为了使ak最先出栈,那么ai和aj一定在ak之后出栈,若顺次放进同一个栈,那么aj必然在ai之前出栈,不满足题意。因此遇到这种情况ai和aj一定分别放入两个栈中。
据此,只要存在i<j<k,有ak<ai<aj,那么ai和aj一定在不同栈中。这样就构成了一个二分图。
扫描一遍,确定那些数对不能在同一栈中,确定互斥关系。若不能构成二分图,那么就不可排序。否则在判断过程中染色,确定不同数在哪个栈中,模拟排序过程,每次等到当前排到的数进栈后把能出栈的都出栈。
Code
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
| #include <bits/stdc++.h> #define MAX_N 1000 using namespace std; vector <int> G[MAX_N+5]; int n, a[MAX_N+5], mi[MAX_N+5], col[MAX_N+5]; void DFS(int u) { for (auto v : G[u]) { if (!col[v]) col[v] = -col[u], DFS(v); if (col[u] == col[v]) {puts("0"); exit(0);} } } void prt() { int cur = 1; stack <int> sa, sb; for (int i = 1; i <= n; i++) { if (col[i] == 1) putchar('a'), putchar(' '), sa.push(a[i]); else putchar('c'), putchar(' '), sb.push(a[i]); for (; !sa.empty() && sa.top() == cur; sa.pop(), cur++) putchar('b'), putchar(' '); for (; !sb.empty() && sb.top() == cur; sb.pop(), cur++) putchar('d'), putchar(' '); for (; !sa.empty() && sa.top() == cur; sa.pop(), cur++) putchar('b'), putchar(' '); } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", a+i); mi[n+1] = 0x3f3f3f3f; for (int i = n; i; i--) mi[i] = min(a[i], mi[i+1]); for (int i = 1; i <= n; i++) for (int j = i+1; j <= n; j++) if (a[i] < a[j] && mi[j+1] < a[i]) G[i].push_back(j), G[j].push_back(i); for (int i = 1; i <= n; i++) if (!col[i]) col[i] = 1, DFS(i); prt(); return 0; }
|