双栈排序 图论

题目描述

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


 

首先我们看到两个栈,想到用二分图来做,然后我们考虑怎么建图,要依据一个神奇的规则,然后我们建好图后就开始染色,最后在输出。

代码:

#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;
}

 

posted @ 2017-09-10 15:38  GSHDYJZ  阅读(181)  评论(0编辑  收藏  举报