附: 题目链接 vijos 1605 地址:https://www.vijos.org/p/1605
思路:
引:将问题先简化为单栈排序,因为双栈排序也就是两个单栈同时进行排序,要考虑的是:哪些点放在一个栈里面排序;
一、所以先来考虑单栈排序:
在栈的时候,有提到:栈是先进后出的 (当然,指的是在它出栈之前如果有元素在它上面,则它是后出的),
所以就有:对于 i < j ,设 p [ x ] 为第 x 个进栈的元素,如果p[ i ] < p[ j ] 也就是说:按照题目要求的按顺序出栈,小的
要先出,p[ i ]要先出,所以 p[ i ] 必须在 p[ j ]进栈前出栈,不然 p[ i ]必须在p[ j ] 出栈后才能出,这样就不能满足按顺序,
但同样的,p[ i ]能够出栈的前提是: 所有比它小的元素均已出栈;这时就能发现,如果在 j之后存在比 p[ i ] 小的元素,则单
栈排序不可进行。
并且只要不存在这种情况,则单栈排序一定能进行,因为对于任意 p[ x ] 在它必须出栈的时候不存在限制它出栈的元素,然
后按照进栈顺序进行模拟就可完成排序过程。
二、现在再来看看双栈排序:
在写代码之前,必须明确的是:双栈排序就是同时给出两个单栈的进栈顺序,并且没告知哪些元素是一个栈的,哪些元素不是
一个栈的,所以代码的首要任务就是对两个单栈进行元素的分配,并且是两个单栈都能进行排序的分配,如果找不出就输出零。
联系第一步的思考,就是说对于每一对如上述所说的点,如果上述情况存在,那么这两个点不能在同一个单栈里面,所以就可
以通过染色对栈进行分配。
三、完成分配后:
基本就是纯模拟了,同时模拟两个栈的操作,按颜色分成两个栈,然后按 操作 a > 操作 b > 操作 c > 操作 d 的优先级进行
贪心模拟。
注:本代码用的不是这种一个个操作去贪心的科学模拟方法(—> _ —>)而是用了一种极不科学的打法(甚至连下标都不小
心打错的打法)但是对于任何随机数据和科学打法的结果却是一样一样的— —! 并且vijos上总耗时0毫秒AC— —!至今不知为
何如此拙计— —!
四、算法实现:
将所有冲突的元素连上一条线(用邻接表、哈希神马都可以,线不会多到那里去,本代码采用哈希),全部连完后,从第一个
点开始到第n 个点,如果没染色就对它进行染色,并把与它矛盾的点染上另一个颜色,如果染色过程中出现将一个有颜色的点染成
另一种颜色的情况,那么就无解,因为至少有其中一个单栈无法进行排序。(其实染色的过程就是在解决最后问题中对元素的分配
)。
最后用贪心模拟一遍就O拉~
五、代码:
I、 无注释的压行压得有点丧心病狂的33行代码~~~其实也没多丧心病狂— —!函数过程之间的空行还是有的— —!定义全
局变量时数组的变量也分两行了— —:
1 #include<cstdio> 2 #include<algorithm> 3 int p [1010 ],col[1010 ],Min[1010 ],pai[3][1010],l[3],wei[10010],las[10010],too[10010]; 4 int n,t=0,should=1; 5 6 void line(int x,int y) { 7 las[++t] = wei[x]; wei[x] = t; too[t] = y; 8 las[++t] = wei[y]; wei[y] = t; too[t] = x; 9 } 10 11 void draw(int x,int c) { 12 if (!col[x] ) col[x]=c; else 13 if ( col[x]!=c) {printf("0");exit(0);} else return; 14 for (int i=wei[x]; i; i=las[i]) draw(too[i],3-c); 15 } 16 17 int main() { 18 scanf("%d",&n); for (int i=1 ; i<=n; i++) scanf("%d",&p[i]); 19 Min[n] = p[n]; for (int i=n-1; i>=1; i--) Min[i]=std::min(Min[i+1],p[i]); 20 pai[1][0]=1002; col[n+1]=1; pai[2][0]=1002; p[n+1]=1001; 21 for (int i=1 ; i<=n-2; i++) 22 for (int j=i+1; j<=n-1; j++) 23 if(p[i]<p[j]&&Min[j+1]<p[i]) line(i,j); 24 for (int i=1 ; i<=n ; i++) 25 if ( !col[ i ] ) draw(i,1); 26 for (int i=1 ; i<=n+1; i++) { 27 while (1) 28 if ( pai[1][l[1]] == should ) {should++; l[1]--; printf("b ");} else 29 if ( pai[2][l[2]] == should ) {should++; l[2]--; printf("d ");} else break; 30 pai[ col[i] ][ ++l[ col[i] ] ]=p[i]; 31 if (i<n+1) printf("%c ", char(2*col[i]+95) ); 32 } 33 }