本来以为是一道排序题,然而看了一眼标签
woc,图论题,一脸懵逼~~~~~~
题意:给你两个栈,四种操作
操作 a
如果输入序列不为空,将第一个元素压入栈 $S_1$
操作 b
如果栈$S_1$不为空,将$S_1$ 栈顶元素弹出至输出序列
操作 c
如果输入序列不为空,将第一个元素压入栈$S_2$
操作 d
如果栈 $S_2$ 不为空,将$S_2$ 栈顶元素弹出至输出序列
然后,给你1-n的一个全排列,问能否双栈排序
能:输出字典序最小的操作序列,否则输出0
正解:二分图染色 --------------------by@ Harry·Shaun·Wang(lg)
1.首先考虑一个简单情况:单栈排序:
若存在一个k,使得i<j<k且a[k]<a[i]<a[j],则a[i]和a[j]不能压入一个栈中
用f[i]维护后缀最小值
状态:f[i]=min(a[i],a[i+1], ... ,a[n])
边界条件:f[n+1]=INF;
状态转移方程:f[i]=min(f[i+1],a[i]);
于是上述判断就转化为了f[j+1]<a[i] && a[i]<a[j]
把时间复杂度从$O(n^3)$优化到了$O(O^2)$
2.扩展到双栈排序:
如果a[i]和a[j]不能在一个栈内,即连接一条i与j之间的无向边,接下来我们只需要判断这个图是否为二分图
由于题目中说编号的字典序要尽可能的小,那么就把编号小的尽可能放到stack1
判断二分图的方法可以采用黑白染色的方式,先从编号小的开始染,第一个顶点染成黑色,相邻的顶点染成不同的颜色,如果发现黑白冲突,那么说明这个图不是一个二分图,是不合法的,输出0.
(DFS或BFS染色均可)
3.染色后所有黑色的点进stack1,所有白色的点进stack2,最后模拟输出过程就可以了.
详见代码
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; #define olinr return #define love_nmr 0 #define _ 0 int f[1050]; int xl[1050]; int n; int col[1050]; vector<int> G[1050]; queue<int> q; struct node { int st[1050]; int tp; node() { memset(st,0,sizeof st); tp=0; } void pop() { tp--; } void push(int x) { tp++; st[tp]=x; } bool empty() { return tp==0; } int top() { return st[tp]; } }; node A; node B; /*----------------------------olinr love nmr---------------------------------------*/ inline void bfs(int now) { while(!q.empty()) q.pop(); q.push(now); col[now]=1; while(!q.empty()) { int tp=q.front(); q.pop(); int siz=G[tp].size(); for(int i=0;i<siz;i++) { int go=G[tp][i]; if(col[go]==-1) { col[go]=col[tp]^1; q.push(go); } else if(!(col[go]^col[tp])) { cout<<0; exit(0); } } } } int main() { ios::sync_with_stdio(false); cin>>n; f[n+1]=0x7fffffff; for(int i=1;i<=n;i++) cin>>xl[i]; for(int i=n;i>=1;i--) f[i]=min(f[i+1],xl[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { if(xl[i]>f[j+1]&&xl[i]<xl[j]) { G[i].push_back(j); G[j].push_back(i); } } memset(col,-1,sizeof col); for(int i=1;i<=n;i++) if(col[i]==-1) bfs(i); int tot=1; for(int i=1;i<=n;i++) { if(col[i]==1) { cout<<"a "; A.push(xl[i]); } else { cout<<"c "; B.push(xl[i]); } while((!A.empty()&&A.top()==tot)||(!B.empty()&&B.top()==tot)) { if((!A.empty()&&A.top()==tot)) { A.pop(); cout<<"b "; } else { B.pop(); cout<<"d "; } tot++; } } olinr ~~(0^_^0)+love_nmr; }