2018.10.30【NOIP2008】【洛谷P1155】双栈排序(二分图染色)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83552259

传送门


解析:

首先需要知道单栈排序的结论:
一个序列如果存在 i < j < k i<j<k a k < a i < a j a_k<a_i<a_j ,肯定无法完成单栈排序。

证明十分显然,我们需要将 k k 排序,要先将 i , j i,j 压入栈中,然而压入了 j j 之后就无法把 i i 从栈里面弹出来了,所以肯定gg。

而判断可以采用预处理后缀最大值的方式来把复杂度降为 O ( n 2 ) O(n^2)

那么不能单栈排序的考虑怎么双栈排序。

首先所有有上面这个情况的数对 a i , a j a_i,a_j 不能放在一个栈中排序,反之一定可以。所以可以采用二分图染色的方式判断。

为了使字典序最小,我们将先染的颜色尽可能放在第一个栈中,之后能弹栈时尽量弹就行了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=1003;

vector<int> e[N];
int col[N];
inline void dye(int u){
	for(int re i=0;i<e[u].size();++i){
		int re v=e[u][i];
		if(!~col[v]){
			col[v]=col[u]^1;
			dye(v);
		}
		else if(col[v]!=(col[u]^1))cout<<0,exit(0);
	}
}

stack<int> s1,s2;
int n,now;
int a[N],minn[N];
signed main(){
	memset(col,-1,sizeof col);
	n=getint();
	for(int re i=1;i<=n;++i)a[i]=getint();
	minn[n+1]=0x3f3f3f3f;
	for(int re i=n;i;--i)minn[i]=min(a[i],minn[i+1]);
	for(int re i=1;i<=n;++i){
		for(int re j=i+1;j<=n;++j){
			if(a[i]<a[j]&&a[i]>minn[j+1]){
				e[i].push_back(j);
				e[j].push_back(i);
			}
		}
	}
	now=1;
	for(int re i=1;i<=n;++i)if(!~col[i])col[i]=1,dye(i);
	for(int re i=1;i<=n;++i){
		if(col[i])s1.push(a[i]),pc('a');
		else s2.push(a[i]),pc('c');
		pc(' ');
		while(true){
			if((s1.empty()||s1.top()!=now)&&(s2.empty()||s2.top()!=now))break;
			if(!s1.empty()&&s1.top()==now)pc('b'),s1.pop();
			else pc('d'),s2.pop();
			pc(' ');
			++now;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83552259
今日推荐