题目链接
https://www.acwing.com/problem/content/description/155/
题目
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希望知道其中字典序最小的操作序列是什么。
输入格式
输入的第一行是一个整数p,代表有p组测试数据。
每组测试数据的第一行有一个正整数n,第二行有n个用空格隔开的正整数,构成一个1~n的排列。
输出格式
输出共p行,如果输入的排列不是”可双栈排序排列”,输出数字0。
否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
数据范围
1≤n≤1000
输入样例:
1
3
2 3 1
输出样例:
a c a b b d
题解
二分图匹配问题。
考虑一下什么情况两个数不能放在同一个栈中:
如果i<j<k并且a[k]<a[i]<a[j], 那么a[i]和a[j]不能放在同一个栈中。因为a[i]>a[k] ,i<k.那么i必须等到a[k]出栈之后a[i]才能出栈,但是如果a[j]和a[i]在同一个栈中,因为j>i.那么a[j]在a[i]之前出栈,但a[j]>a[i],那么出栈后的元素就不是有序的了。
把不能放在同一个栈中的元素用边连起来,就变成一个二分图匹配问题,有边相连的两个点不能是同一种颜色。颜色分别为0和1,优先使用0染色,用0染色的表示a操作,用1染色的表示c操作。
代码
#include<algorithm>
#include <iostream>
#include<stack>
#include<cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e3+5;
int g[maxn][maxn];
int a[maxn];
int minn[maxn];
int color[maxn];
int n;
bool dfs(int u,int x){
color[u]=x;
for(int i=1;i<=n;i++){
if(g[u][i]){
if(color[i]==x) return false;
if(color[i]==-1&&!dfs(i,!x)) return false;
}
}
return true;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
minn[n+1]=n+1;
for(int i=n;i>=1;i--) minn[i]=min(minn[i+1],a[i]);
memset(g,0,sizeof g);
memset(color,-1,sizeof color);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i]<a[j]&&minn[j+1]<a[i]){
g[i][j]=g[j][i]=1;
}
}
}
bool flag=true;
for(int i=1;i<=n;i++){
if(color[i]==-1){
if(!dfs(i,0)){
flag=false;
break;
}
}
}
if(!flag){
puts("0");
continue;
}
stack<int> sta,sta2;
int now=1;
for(int i=1;i<=n;i++){
if(color[i]==0){
sta.push(a[i]);
printf("a ");
}else{
sta2.push(a[i]);
printf("c ");
}
while(true){
if(sta.size()&&sta.top()==now){
sta.pop();
now++;
printf("b ");
}else if(sta2.size()&&sta2.top()==now){
sta2.pop();
now++;
printf("d ");
}else{
break;
}
}
}
printf("\n");
}
return 0;
}