【NOIP2008提高组】双栈排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38083668/article/details/83066551

题目背景

NOIP2008提高组试题4。

题目描述

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,2,3,4)就是一个“可双栈排序排列”,而(2,3,4,1)不是。下图描述了一个将(1,3,2,4)排序的操作序列:

当然,这样的操作序列有可能多个,对于上例(1,2,3,4),是另外一个可行的操作序列。Tom 希望知道其中字典序最小的操作序列是什么。

输入格式

输入两行:
第一行是一个整数 n 。 
第二行有 n 个用空格隔开的正整数,构成一个 1~n 的排列。

输出格式

输出一行,如果输入的排列不是“可双栈排序排列”,输出数字 0;否则输出字典最小的操作序列,每个操作之间用空格隔开,行尾没有空格。

样例数据 1

输入

4
1 3 2 4

输出

a b a a b b a b

样例数据 2

输入

4
2 3 4 1

输出

0

样例数据 3

输入

3
2 3 1

输出

a c a b b d

备注

【数据范围】 
30% 的数据满足:n<=10 
50% 的数据满足:n<=50 
100% 的数据满足:n<=1000

解析:
       就算知道是二分图染色还是不会TT。

       首先考虑怎么判断是否有解。

       a [ i ] 和 a [ j ] 不能压入同一个栈(在同一个栈中出现过)⇔ 存在一个k,使得 i < j < k 且 a [ k ] < a [ i ] < a [ j ]

       严格证明就比较复杂了,我就说如何感性理解吧(反正在考场上也没几个人会去严格证明)。

       因为一个数只能进出一次,k 要排在前面所以弹出 k 时 i 和 j 都在栈里,如果两者在同一个栈弹出后顺序就错误了,然后找不到除这种情况外的反例,于是就这样了。。。

       所以如果输入数据不能使得所有限制成立则无解,然后就可以转化成二分图染色来判定,不能在同一个栈中就连边。

       关于输出答案,因为要让字典序最小肯定是尽量加在S1里面,实在不行加进S2。

代码:

#include <bits/stdc++.h>
using namespace std;

const int Max=1010;
int n,m=1,size,tot1,tot2,p1[Max],p2[Max];
int first[Max],f[Max],num[Max],vis[Max];
struct shu{int to,next,len;}edge[Max*Max];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline void build(int x,int y)
{
	edge[++size].next=first[x],first[x]=size,edge[size].to=y;
	edge[++size].next=first[y],first[y]=size,edge[size].to=x;
}

inline void pre()
{
	f[n]=num[n];
	for(int i=n-1;i>=1;i--) f[i]=min(f[i+1],num[i]);
	for(int i=1;i<=n;i++)
	  for(int j=i+1;j<=n;j++)
	    if(f[j]<num[i]&&num[i]<num[j]) build(i,j);
}

inline bool dfs(int p,int color)
{
	vis[p]=color;
	for(int u=first[p];u;u=edge[u].next)
	{
	  int to=edge[u].to;
	  if(!vis[to]) dfs(to,3-color);
	  else if(color==vis[to]) return 0;
	}
	return 1;
}

int main()
{
	n=get_int();
	for(int i=1;i<=n;i++) num[i]=get_int();
	pre();
	for(int i=1;i<=n;i++) if(!vis[i]&&!dfs(i,1)) {puts("0");return 0;}
	for(int i=1;i<=n;i++)
	{
	  if(vis[i]==1)p1[++tot1]=num[i],printf("a ");
	  else p2[++tot2]=num[i],printf("c ");
	  while(m==p1[tot1]||m==p2[tot2])
	  {
	  	if(m==p1[tot1]) tot1--,printf("b ");
	  	else tot2--,printf("d ");
	  	m++;
	  }
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/83066551
今日推荐