双栈排序 图论
题目描述
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; }
PEACE