首页 写随笔

cdcq(本博客废弃!现用博客:https://www.cnblogs.com/cdcq/)

本博客废弃!现用博客:https://www.cnblogs.com/cdcq/

导航

【NOIP2008】双栈排序

感觉看了题解还是挺简单的,不知道当年chty同学为什么被卡了呢么久……所以说我还是看题解了

原题:

 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希望知道其中字典序最小的操作序列是什么。

n<=1000

 

 非常重要的核心结论:S[i],S[j]两个元素不能进入同一个栈 <=> 存在k,满足i<j<k,使得S[k]<S[i]<S[j]

证明略(逃

(其实我连题都没研究,只是看懂这个结论,代码很容易就写出来……)

然而酱紫判断是n^3的,会T,可以用一个很简单的前缀和DP,用f[i]表示i到n的最小值,就可以用O(n^2)的时间完成判断辣

然后限制条件有了,只有两个栈,就用二分图染色

为了使字典序最小,要优先进入1栈,所以在染色的时候要使用邻接矩阵,然后按照序号递增的顺序找边染色,且第一个点要染成1栈的颜色

最后栈的分配方案给出来了,就可以用一个temp来模拟排序后的递增序列,枚举i到n,先把a[i]根据颜色进栈,然后while栈1或栈2的栈头==temp就出栈,为了使字典序最小要先出1栈

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 const int oo=168430090;
 8 /*struct ddd{int next,y;}e[2100000];int LINK[210000],ltop=0;
 9 inline void insert(int x,int y){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;}*/
10 bool e[1100][1100];//因为要按编号递增染色,所以用邻接矩阵
11 int n,a[1100];
12 int f[1100];
13 int color[1100];
14 int zhana[1100],topa=0,zhanb[1100],topb=0;
15 bool dfs(int x,int y){
16     if(color[x]!=-1 && color[x]==color[y])  return false;
17     if(color[x]==!color[y])  return true;
18     color[x]=!color[y];
19     for(int i=1;i<=n;i++)if(e[x][i] && i!=y && !dfs(i,x))  return false;
20     return true;
21 }
22 int main(){//freopen("ddd.in","r",stdin);
23     memset(e,0,sizeof(e));
24     memset(color,-1,sizeof(color));
25     cin>>n;
26     for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
27     f[n+1]=oo;
28     for(int i=n;i>=1;i--)  f[i]=min(a[i],f[i+1]);
29     for(int i=1;i<n;i++)
30         for(int j=i+1;j<=n;j++)if(a[i]<a[j] && f[j+1]<a[i])
31             e[i][j]=e[j][i]=true;
32     for(int i=1;i<=n;i++)if(color[i]==-1 && !dfs(i,0)){  cout<<0<<endl;  return 0;}
33     int temp=1;//使用temp可以很方便地模拟递增序列
34     for(int i=1;i<=n;i++){
35         if(!color[i])  zhana[++topa]=a[i],printf("a ");
36         else  zhanb[++topb]=a[i],printf("c ");
37         while((topa && zhana[topa]==temp) || (topb && zhanb[topb]==temp)){
38             if(topa && zhana[topa]==temp)  topa--,printf("b ");
39             else  topb--,printf("d ");
40             temp++;
41         }
42     }
43     return 0;
44 }
View Code

 

posted on 2016-10-07 21:53  cdcq_old  阅读(393)  评论(0编辑  收藏  举报