by GeneralLiu
题目大意
给出一个1~n的排列
能否通过两个栈的出栈进栈操作
完成从大到小排序
如果不能 输出 0
能就 输出字典序最小的操作方案
(题目要求详情见洛谷链接 没错,就是上面那个)
假设现在你已经了解 题目的要求 以及细节
那我就在博客 try 着去重现
培训时 mzx dalao 讲课时的情景
选中下文查看分析
设 a<b<c<d...<n ;也可以理解为 a=1,b=2 , c=3.....
“ 先不要管 双栈排序
先想想 单栈排序
(一个 稍微凌乱点的 序列能单栈,
就是 " b a d c... n "这种不是太乱的)
当然,大多数情况是不能单栈排序的,
(就是出现形如 " b c a " 这种又乱了些序列时)
当单栈排序行不通时
就试试双栈排序
(拿上一个" b c a"来讲
如果双栈 可以 b进栈1 c进栈2 a进栈1 a出栈1 b出 c出...
这种不是很恶心的 序列 是可以双栈的)
那双栈什么时候也会虚呢?
(其实双栈很容易虚的
不信 把上一个" b c a "加一个d
变成" b c d a "试试
点到为止)
现在对于本题来说已经可以了
(不能双栈直接 输出 NO
能的话 优先 栈1 字典序最小嘛)
但还是拓展一下
双栈虚了,三栈行不?
(咦,刚才的 " b c d a "用三栈可以耶
但再加一个 e 的话
就是 " b c d e a "
那么三栈也虚了)
......”
好了 “聪明的读者,看到这你一定明白了”by 刘汝佳
假设有 a b c d e 五个数
出现 b c d a 时 双栈不能解决 可三栈能
出现 b c d e a 时三栈就不能了
到这儿,规律已出
现在 能否用 N 栈排序的问题已经解决
那么就剩字典序最小的问题了
其实贪心去优先用第一个栈就好
现在思路已经 缕出
至于代码实现
分两步:
1:判断能否双栈
维护一个mind[]数组 mind[i] 表示末尾 i 个数的最小值 // 代码 24行
若 满足一个 i<j<k && s[k]<s[i]<s[j] //代码 25~28 行
说明 第 i 和第 j 个不能单栈
就 把 i 到 j 连一条边 表示 i ,j 不能同栈
最后抽象成 二分图判断 即可 // 代码 29~31行
2:输出操作序列
依题目要求即可
不必细说
看代码
代码
1 #include<iostream> 2 #include<stack> 3 #include<algorithm> 4 #define N 1005 5 using namespace std; 6 int mind[N],n,s[N],color[N],mp[N][N]; 7 stack<int> s1,s2;//两个栈 8 void dfs(int u,int c){ // 二分图 染色 9 color[u]=c; 10 for(int i=1;i<=n;i++) 11 if(mp[u][i]){ 12 if(color[i]==c){ // 不能双栈 退出 13 cout<<0; 14 exit(0); 15 } 16 if(!color[i]) 17 dfs(i,-c); 18 } 19 } 20 int main(){ 21 cin>>n; 22 for(int i=1;i<=n;i++)cin>>s[i]; 23 mind[n+1]=N; 24 for(int i=n;i>=1;i--)mind[i]=min(mind[i+1],s[i]);//维护mind[] 25 for(int i=1;i<n;i++) // 枚举 判断 能否单栈 26 for(int j=i+1;j<=n;j++) 27 if(s[i]<s[j]&&mind[j+1]<s[i]) 28 mp[i][j]=mp[j][i]=1; // 连边 29 for(int i=1;i<=n;i++) 30 if(!color[i]) 31 dfs(i,1);// 优先 染色 为1 进栈1 保证 字典序 最小 32 int aim=1; // 表示 目前应该是 该aim 出栈 (因为是个排列嘛) 33 for(int i=1;i<=n;i++){ // n 次进栈 34 if(color[i]==1){ 35 cout<<"a "; 36 s1.push(s[i]); 37 } 38 else{ 39 cout<<"c "; 40 s2.push(s[i]); 41 } 42 // 该出栈时 就出栈 诶~ 43 while( (!s1.empty()&&s1.top()==aim) || (!s2.empty()&&s2.top()==aim) ){ 44 if(!s1.empty()&&s1.top()==aim){ 45 cout<<"b "; 46 s1.pop(); 47 } 48 else{ 49 cout<<"d "; 50 s2.pop(); 51 } 52 aim++; // 出一个 加一个 53 } 54 } 55 return 0; 56 }