双栈排序(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)就是一个“可双栈排序序列”,而(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希望知道其中字典序最小的操作序列是什么。

【样例输入1】

4

1 3 2 4

【样例输出1】

a b a a b b a b

【样例输入2】

4

2 3 4 1

【样例输出2】

0

【样例输入3】

3

2 3 1

【样例输出3】

a c a b b d

【解题思路】

本题为NOIP2008提高组第四题,初看觉得这应该是有史以来最水的提高组最后一题了,这不是模拟吗?只不过模拟的东西多了一点而已,然而,当我写着写着,就发现模拟的有点不对劲了……

好吧,这道题的正解应该是图的染色+模拟……

是的,没错,你没有看错,第四题居然要模拟!!!

染色其实是一个深搜的过程,染色是为了区分程序从头到尾始终不能放在一个栈中的数,然后为了保证是字典序最小,因此尽量往栈1中放,如果有始终无法放到同一个栈中的数被放到了同一个栈(这里的被放到同一个栈是指的染成同一种颜色),那么就无解,输出0。(染色的方法可以百度floodfill或者种子染色法)

那么问题来了……挖掘机哪家……不对……怎么区分始终不能放在一个栈中的数呢?

如果存在k使得i<j<k且ak<ai<aj则ai和aj不能进入同一个栈。

我们可以手推一下,如果k>j>i说明,j在i的后面进栈,k在j的后面进栈,而此时ai<aj,那么如果ai和aj进了同一个栈,那么就会是aj先出栈,就肯定不是从小到大排好序的了。

染完色后就好办了,直接模拟进栈出栈的过程……如果是最小值,就出,否则就进,然后因为已经染了色了,根据染的色判断它是进(出)栈1还是栈2,然后输出相应的字符即可。

现在还有一个最最担心的问题,怎么确定这个数是不是当前需要出栈的数(即最小值)?好吧……其实是我眼睛瞎了,是的,我为此纠结了半天,然后看题目……一个1~n的排列P……直接最小值赋值为1,然后出栈了就Inc……

【代码实现】

 1 uses math;
 2 var flag:array[1..1000,1..1000] of boolean;
 3     q1,q2,color,a,f:array[1..1001] of longint;
 4     n,i,j,sum,t1,t2:longint;
 5 procedure dfs(x,c:longint);
 6 var i:longint;
 7 begin
 8  color[x]:=c;
 9  for i:=1 to n do
10   if flag[x,i] then
11    begin
12     if color[i]=c then
13      begin
14       writeln(0);
15       halt;
16      end;
17     if color[i]=0 then
18      dfs(i,3-c);
19    end;
20 end;
21 begin
22  readln(n);
23  for i:=1 to n do
24   read(a[i]);
25  f[n+1]:=maxlongint;
26  for i:=n downto 1 do
27   f[i]:=min(a[i],f[i+1]);
28  for i:=1 to n-1 do
29   for j:=i+1 to n do
30    if (a[i]<a[j])and(f[j+1]<a[i]) then
31     begin
32      flag[i,j]:=true;
33      flag[j,i]:=true;
34     end;//初始化,哪些是始终无法进同一个栈的
35  for i:=1 to n do
36   if color[i]=0 then
37    dfs(i,1);//给每一个数染色
38  sum:=1;
39  for i:=1 to n do
40   begin
41    if color[i]=1 then
42     begin
43      inc(t1);
44      q1[t1]:=a[i];
45      write(‘a ‘);
46     end
47    else
48     begin
49      inc(t2);
50      q2[t2]:=a[i];
51      write(‘c ‘);
52     end;
53    while ((t1<>0)and(q1[t1]=sum))or((t2<>0)and(q2[t2]=sum)) do
54     begin
55      if (0<>t1)and(q1[t1]=sum) then
56       begin
57        dec(t1);
58        write(‘b ‘);
59       end
60      else
61       begin
62        dec(t2);
63        write(‘d ‘);
64       end;
65      inc(sum);//最小值
66     end;
67   end;//最恶心的模拟……
68 end.
时间: 2024-11-05 23:25:18

双栈排序(codevs 1170)题解的相关文章

二分图 and code1170 双栈排序

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

Noip2008双栈排序

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

LG1155 双栈排序

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

[LuoguP1155]双栈排序_二分图_bfs

双栈排序 题目链接:https://www.luogu.org/problem/P1155 数据范围:略. 题解: 神仙题. 就第一步就够劝退了. 这个二分图非常不容易,首先只有两个栈,不是属于一个就是属于另一个,我们用二分图判断冲突. 然后不能模拟,我们就贪心的bfs就行了,这一步很鬼畜啊.... 原文地址:https://www.cnblogs.com/ShuraK/p/11762283.html

双栈排序(二分图

# 题意通过两个栈,4中操作,实现输入序列升序排序操作a:如果输入序列不为空,将第一个元素压入栈S1操作b:如果栈S1不为空,将S1栈顶元素弹出至输出序列操作c:如果输入序列不为空,将第一个元素压入栈S2操作d:如果栈S2不为空,将S2栈顶元素弹出至输出序列如果一个1~n的排列P可以通过一系列操作使得输出序列为1, 2,…,(n-1), n,Tom就称P是一个”可双栈排序排列”. 操作序列为<a,c,c,b,a,d,d,b>另一个可行的序列为<a,c,c,b,a,d,d,b>如果序

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(

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)就是一个“可

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

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