题目描述
Tom 最近在研究一个有趣的排序问题。如图所示,通过 22 个栈 S_1S1 和 S_2S2,Tom 希望借助以下 44 种操作实现将输入序列升序排序。
操作 aa:将第一个元素压入栈 S_1S1。
操作 bb:将 S_1S1 栈顶元素弹出至输出序列。
操作 cc:将第一个元素压入栈 S_2S2。
操作 dd:将 S_2S2 栈顶元素弹出至输出序列。
如果一个 1\sim n1∼n 的排列 PP 可以通过一系列合法操作使得输出序列为 (1,2,\cdots,n-1,n)(1,2,⋯,n−1,n),Tom 就称 PP 是一个“可双栈排序排列”。例如 (1,3,2,4)(1,3,2,4) 就是一个“可双栈排序序列”,而 (2,3,4,1)(2,3,4,1) 不是。下图描述了一个将 (1,3,2,4)(1,3,2,4) 排序的操作序列:\texttt {a,c,c,b,a,d,d,b}a,c,c,b,a,d,d,b。
当然,这样的操作序列有可能有几个,对于上例 (1,3,2,4)(1,3,2,4),\texttt{a,b,a,a,b,b,a,b}a,b,a,a,b,b,a,b 是另外一个可行的操作序列。Tom 希望知道其中字典序最小的操作序列是什么。
输入格式
第一行是一个整数 nn。
第二行有 nn 个用空格隔开的正整数,构成一个 1\sim n1∼n 的排列。
输出格式
共一行,如果输入的排列不是“可双栈排序排列”,输出 0
。
否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
输入数据 1
4
1 3 2 4
Copy
输出数据 1
a b a a b b a b
Copy
输入数据 2
4
2 3 4 1
Copy
输出数据 2
0
Copy
输入数据 3
3
2 3 1
Copy
输出数据 3
a c a b b d
Copy
数据范围与约定
30\%30% 的数据满足:n\le10n≤10。
50\%50% 的数据满足:n\le50n≤50。
100\%100% 的数据满足:n\le1000n≤1000。
NOIP 2008 提高组 第四题
代码:
#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\n");
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;
}