• 【NOIP2008】双栈排序


    Description

    Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和s2,Tom希望借助以下4种操作实现将输入序列升序排序。

    1、操作a
    如果输入序列不为空,将第一个元素压入栈S1
    2、操作b
    如果栈S1不为空,将S1栈顶元素弹出至输出序列
    3、操作c
    如果输入序列不为空,将第一个元素压入栈s2
    4、操作d
    如果栈S2不为空,将S2栈顶元素弹出至输出序列
    如果一个1~n的排列P可以通过一系列操作使得输出序列为l,2,…,(n-1),n,Tom就称P是一个“可双栈排序排列”。例如 (1,3,2,4)就是一个“可双栈排序排列”,而(2,3,4,1)不是。下图描述了一个将(1,3,2,4)排序的操作序 列:

    当然,这样的操作序列有可能有多个,对于上例(1,3,2,4),是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。

    solution

    好难的题啊.
    分析一个栈的情况:只能是一个或多个递减连续序列组成的,如 (3,2,1,6,5,4,9,8,7),如果 (3,2,1) 之间出现了 (3,5,1) 的情况,就会存在问题,严格的讲,就是满足 (i<j,a[i]<a[j]),且 (j) 后面存在比 (i) 小的数 这样的二元组 ((i,j)),但是双栈排序就可以很好的解决,我们需要把每一个元素分配给两个栈,然后模拟单栈排序的过程即可,至于分配的条件:如果我们把 ((i,j)) 连边,那么有连边的不能二元组在同一个集合中,这就是二分图的定义,我们二分图染色一下即可,字典序的问题只要我们把前面的元素尽量分给第一个栈就可以满足最小了

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=1005;
    int n,a[N],dp[N],num=0,head[N],to[N*N*2],nxt[N*N*2],col[N];
    
    void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    
    inline void dfs(int x){
    	for(int i=head[x];i;i=nxt[i]){
    		int u=to[i];
    		if(col[u]){
    			if(col[u]+col[x]!=3){puts("0");exit(0);}
    			continue;
    		}
    		col[u]=3-col[x];
    		dfs(u);
    	}
    }
    
    int now=1,st[N],skt[N],top=0,sktop=0;
    inline void P(char c){putchar(c);putchar(' ');}
    inline void solve(int x){
    	if(col[x]==1)st[++top]=a[x],P('a');
    	else skt[++sktop]=a[x],P('c');
    	while((top && st[top]==now) || (sktop && skt[sktop]==now)){
    		if(st[top]==now)top--,P('b');
    		else if(skt[sktop]==now)sktop--,P('d');
    		now++;
    	}
    }
    
    void work()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    	dp[n]=a[n];dp[n+1]=N;
    	for(int i=n-1;i>=1;i--)dp[i]=Min(dp[i+1],a[i]);
    	
    	for(int i=1;i<=n;i++){
    		for(int j=i+1;j<=n;j++){
    			if(a[i]<a[j] && a[i]>dp[j])
    				link(i,j),link(j,i);
    		}
    	}
    	for(int i=1;i<=n;i++)
    		if(!col[i]){
    			col[i]=1;
    			dfs(i);
    		}	
    	for(int i=1;i<=n;i++)solve(i);
    }
    
    int main()
    {
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    P7771 【模板】欧拉路径
    远程服务器运行代码命令(后台执行 及时输出)
    服务器显存溢出
    指定python环境下pip安装包
    语音信号处理
    Es 常用命令
    MySQL常用命令
    Mysql数据按天分区,定期删除,及分区索引
    查看Mysql正在执行的事务、锁、等待
    git忽略提交文件 IT
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7810293.html
Copyright © 2020-2023  润新知