来源:牛客网
文章目录
- 题目描述
- 题意:
- 题解:
- 代码:
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
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希望知道其中字典序最小的操作序列是什么。
输入描述:
第一行是一个整数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
题意:
有四种操作,问如何操作可以实现将输入序列升序排序
四种操作分别是:
操作a:如果输入序列不为空,将第一个元素压入栈S1
操作b:如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c:如果输入序列不为空,将第一个元素压入栈S2
操作d:如果栈S2不为空,将S2栈顶元素弹出至输出序列
题解:
貌似二分图可以做(不过我还没看懂)
首先推出规律:
如果两个数 i,j(i≤j)i,j(i≤j) 不能被放入同一个栈中,当且仅当存在 k,k>jk,k>j, 且 q[k]<q[i]<q[j]q[k]<q[i]<q[j]。
现在有两个栈,我们只需要将满足这个条件的点各自归到一边,中间连一条线,用经典的染色法判断是否为二分图,若是则按照颜色入栈,
若不是则说明不能完成
代码:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<stack>
#include<cmath>
#define maxn 1004
using namespace std;const int inf=19260817;
int n,num;
int color[maxn];
int t[maxn]; //要排序的元素的存储
int s[maxn]; //判断两个数字是否满足规则
bool flag,e[maxn][maxn];void paint(int x,int c){ //DFS进行染色color[x]=c;for(int i=1;i<=n;i++){if(e[x][i]){ //查找相邻点 if(color[i]==c) flag=false; //若相邻点颜色相同,则错误if(!color[i]) paint(i,3-c); //若未染过色,对其染色,3-c结果为1,2,表示1与2号栈}}
}void make(){ //创造二分图s[n+1]=inf; for(int i=n;i>=1;i--){s[i]=t[i];if(s[i+1]<s[i])s[i]=s[i+1];}for(int i=1;i<n;i++){for(int j=i+1;j<n;j++){if(t[i]<t[j] && s[j+1]<t[i]){e[i][j]=e[j][i]=1; //按规则创建图}}}for(int i=1;i<=n;i++){ if(!color[i]){ //染色paint(i,1);}}
}void work(){if(flag==false){printf("0\n");return ; }stack<int> stack1,stack2;int now=1;for(int i=1;i<=n;i++){if(color[i]==1){ //入栈stack1.push(t[i]);printf("a "); }else {stack2.push(t[i]);printf("c "); }while((!stack1.empty() && stack1.top()==now) || (!stack2.empty() && stack2.top()==now)){ //判断是否弹出if(!stack1.empty() && stack1.top()==now){stack1.pop();now++;printf("b ");}else{stack2.pop();now++;printf("d "); }}}
}int main(){flag=1;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&t[i]);}make();work(); return 0;
}