【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 }