• 双栈排序


    by  GeneralLiu

    NOIP2008 双栈排序 

     

    题目大意

    给出一个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 }
  • 相关阅读:
    搭建自己的博客(三十一):为评论以及回复添加邮箱提醒
    gl-transitions 【68个转场效果图】
    frei0r-1.7.0 20191207-0d4b342 DLLs
    Win10资源管理器始终使用详细视图模式
    gcc posix sjij for MSYS 9.2.1+
    mingw32-gcc-9.2.1-i686-posix-sjlj-20190904-8ba5c53
    Newtonsoft.Json高级用法
    在线文档预览方案-office web apps
    我的前端学习历程
    我是怎么使用最短路径算法解决动态联动问题的
  • 原文地址:https://www.cnblogs.com/1227xq/p/6827996.html
Copyright © 2020-2023  润新知