题目描述
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】 4 1 3 2 4 【输入样例2】 4 2 3 4 1 【输入样例3】 3 2 3 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
首先我们看到两个栈,想到用二分图来做,然后我们考虑怎么建图,要依据一个神奇的规则,然后我们建好图后就开始染色,最后在输出。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
#define il inline
#define db double
#define min(a,b) ((a)>(b)?(b):(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define MAX 1045
using namespace std;
il int gi()
{
int x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
y=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*y;
}
bool pic[MAX][MAX];//保存二分图的
int color[MAX];//保存每个点的颜色
int temp[MAX];//保存每个数的大小
int small[MAX];//保存i到n中最小的值(用来判断规则)
int n;
bool flag;//判断是否有解
void dfs(int x,int y)
{
color[x]=y;
for(int i=1;i<=n;i++)
{
//如果一条边连到的两个节点颜色相同,则无法建立二分图
if(pic[x][i])
{
if(color[i]==y)
flag=1;
//给下个点染成另外一种颜色,只有两种颜色
if(!color[i])
dfs(i,3-y);
}
}
}
il void init()
{
small[n+1]=2e8;
//记录q[k]
for(int i=n;i>=1;i--)
{
small[i]=temp[i];
if(small[i+1]<small[i])
small[i]=small[i+1];
}
//判断规则
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(temp[i]<temp[j]&&small[j+1]<temp[i])//temp[j]>temp[i]>temp[k]
pic[i][j]=pic[j][i]=1;
//二分图染色
for(int i=1;i<=n;i++)
if(!color[i])
dfs(i,1);
}
il void work()
{
//无法建图
if(flag==1)
{
printf("0\n");
return;
}
//两个栈
int stack1[MAX];
int stack2[MAX];
int head1=0,head2=0;
//只为了少输出一个空格
int count=0;
//判断是否要出栈
int aim=1;
for(int i=1;i<=n;i++)
{
//入栈
if(color[i]==1)
{
stack1[++head1]=temp[i];
printf("a");
if(count<n*2)
printf(" ");
}
else
{
stack2[++head2]=temp[i];
printf("c");
if(count<n*2)
printf(" ");
}
//出栈
while((head1!=0&&stack1[head1]==aim)||(head2!=0&&stack2[head2]==aim))
{
if(head1!=0&&stack1[head1]==aim)
{
head1--;
count++;
aim++;
printf("b");
if(count<n*2)
printf(" ");
}
else
{
head2--;
count++;
aim++;
printf("d");
if(count<n*2)
printf(" ");
}
}
}
printf("\n");
}
int main()
{
freopen("双栈排序.in","r",stdin);
n=gi();
for(int i=1;i<=n;i++)
temp[i]=gi();
init();
work();
return 0;
}