zoukankan      html  css  js  c++  java
  • Vijos1605 NOIP2008 提高组T4 双栈排序 BFS

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - Vijos1605


    题意概括

      有1个1~n的排列,有2个栈,现在通过以下操作,使得出栈序列有序。

      操作a 当前元素入栈<S1>

      操作b 弹出S1栈顶元素

      操作c 当前元素入栈<S2>

      操作d 弹出S2栈顶元素

      如果无法使得出栈序列有序,那么输出0.

      否则输出满足条件的字典序最小的操作序列。


    题解

      首先我们可以证明,任意时刻,任意一个栈中的元素,一定满足自底向上呈降序。

      如果不呈降序呢?

      那么会出现大的先出栈,小的后出栈的情况,所以一定不行。

      我们考虑2个元素a[i],a[j],(i<j)。

      可以得到信息:

      如果a[i]<a[j]那么a[i]先出栈

      否则 a[j]先出栈

      然后好像没有其他信息了。

      问题很严峻。

      于是我们考虑3个元素a[i],a[j],a[k](i<j<k)

      考虑所有情况。

      如果a[i]<a[j]<a[k],那么a[i],a[j]可能在同一个栈中。

      同样,

      如果a[i]<a[k]<a[j],那么a[i],a[j]可能在同一个栈中。

      如果a[j]<a[i]<a[k],那么a[i],a[j]可能在同一个栈中。

      如果a[j]<a[k]<a[i],那么a[i],a[j]可能在同一个栈中。

      如果a[k]<a[j]<a[i],那么a[i],a[j]可能在同一个栈中。(这5中情况都可以有具体操作次序,注意是“可能”)

      但是,

      如果a[k]<a[i]<a[j],那么a[i],a[j]一定不可能在同一个栈中。

      为什么?

      首先a[i]进栈。

      因为a[k]<a[i],所以在a[k]出栈之前,a[i]不能出栈。

      然而因为a[i]<a[j],如果a[i]与a[j]放在同一个栈中,那么会出现题解第一句中表述的不合法情况。

      因此a[i],a[j]一定不会在同一个栈中。

      于是我们可以先确定i,j,然后大力枚举k,按照不在同一个栈中的关系建立无向图。相邻的节点一定不会在同一个栈中。这个操作的复杂度为n^3。

      而实际上,我们可以先预处理一个后缀最小值,那么大力枚举k的时间复杂度就被压缩掉了。

      优化之后,这个操作的复杂度为n^2。

      建图之后,就是匹配栈。

      黑白染色即可。(假设栈1为白色(0),栈2为黑色(1))

      又由于题目要字典序最小的,所以我们尽量给编号小的节点染成白色就可以了。

      于是我们大力跑一遍广搜。

      当然染色的过程中会出现相邻节点颜色相同的情况,那么就是无解,直接输出0。

      广搜完了之后,每一个数字安排的栈位置都已经弄好了。

      然后就是模拟了。

      模拟的时候,还是要注意字典序最小的问题。

      注意按照之前匹配的一定有解的。

      模拟具体过程:

      我们弄一个计数器cnt,表示当前出栈到了哪一个数字。

      对于每次压入元素前,如果栈1的栈顶元素是cnt+1,那么要先将栈1出栈。

      因为,如果当前元素匹配的是栈2,那么自然就是栈1出栈优先。

      如果是栈1,那么元素值一定会比cnt+1要大,不满足最前面的那一条。

      然后,注意对于同一个栈,入栈的优先级一定比出栈高。

      所以,我们尽量提前入栈。

      但是入栈是有条件的,要维持序列降序。

      那么就要先出栈,直到满足降序为止。

      出栈也是有规矩的。要满足cnt+1,所以是两个栈乱序出栈的。

      我的程序貌似有点小问题,但是数据水,过去了……

      具体:

      如果匹配栈2,那么出栈操作之后,满足栈2降序之后,其实有字典序更小的方案。

      因为栈2入栈,是c,而栈1出栈是b,所以栈1先出栈是赚的。但是我忘记判这个情况了。

      然后居然……

      至此,rzO膜拜大佬出据人Orz


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <queue>
    using namespace std;
    const int N=1000+5,Inf=100000;
    struct Stack{
    	int v[N],t;
    	void clear(){
    		t=0;
    	}
    	void push(int x){
    		v[++t]=x;
    	}
    	void pop(){
    		t--;
    	}
    	bool empty(){
    		return t==0;
    	}
    	int top(){
    		if (t==0)
    			return Inf;
    		return v[t];
    	}
    }s1,s2;
    int n,a[N],Min[N],match[N],vis[N],cnt;
    bool g[N][N];
    queue <int> q;
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	Min[n]=10000;
    	for (int i=n-1;i>=1;i--)
    		Min[i]=min(Min[i+1],a[i+1]);
    	memset(g,0,sizeof g);
    	for (int i=1;i<=n;i++)
    		for (int j=i+1;j<=n;j++)
    			if (a[i]<a[j]&&Min[j]<a[i])
    				g[i][j]=g[j][i]=1;
    	memset(vis,0,sizeof vis);
    	for (int i=1;i<=n;i++){
    		if (vis[i])
    			continue;
    		while (!q.empty())
    			q.pop();
    		vis[i]=1,match[i]=0;
    		q.push(i);
    		while (!q.empty()){
    			int x=q.front();
    			q.pop();
    			for (int j=1;j<=n;j++){
    				if (!g[x][j])
    					continue;
    				if (!vis[j]){
    					match[j]=match[x]^1;
    					q.push(j);
    					vis[j]=1;
    				}
    				else if (match[j]==match[x]){
    					printf("0");
    					fclose(stdin);fclose(stdout);
    					return 0;
    				}
    			}
    		}
    	}
    	cnt=0;
    	s1.clear(),s2.clear();
    	for (int i=1;i<=n;i++){
    		while (s1.top()==cnt+1){
    			printf("b ");
    			s1.pop();
    			cnt++;
    		}
    		if (match[i]==0){
    			while (a[i]>s1.top()&&(s1.top()==cnt+1||s2.top()==cnt+1))
    				if (s1.top()==cnt+1){
    					printf("b ");
    					s1.pop();
    					cnt++;
    				}
    				else {
    					printf("d ");
    					s2.pop();
    					cnt++;
    				}
    			s1.push(a[i]);
    			printf("a ");
    		}
    		if (match[i]==1){
    			while (a[i]>s2.top()&&(s1.top()==cnt+1||s2.top()==cnt+1))
    				if (s1.top()==cnt+1){
    					printf("b ");
    					s1.pop();
    					cnt++;
    				}
    				else {
    					printf("d ");
    					s2.pop();
    					cnt++;
    				}
    			s2.push(a[i]);
    			printf("c ");
    		}
    	}
    	while (!s1.empty()||!s2.empty())
    		if (s1.top()<s2.top()){
    			printf("b ");
    			s1.pop();
    		}
    		else {
    			printf("d ");
    			s2.pop();
    		}
    	return 0;
    }
    

      

  • 相关阅读:
    layer弹出层无法关闭问题
    layer iframe层ajax回调弹出layer.msg()
    layer iframe层弹出图片
    php部分基础
    小程序wx:key = “{{*this}}”报错
    运行jar包的命令
    spring aop
    Connection is read-only. Queries leading to data modification are not allowed
    操作录像命令----过程记录与回放
    开机自动登录图形化界面
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NOIP2008T4.html
Copyright © 2011-2022 走看看