zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    类UNIX系统
    wxpython
    新闻
    游戏公司排名
    游戏网站
    3D打印
    python程序报"iccp known incorrect srgb profile" 警告
    python命令行退出
    plc和嵌入式的区别
    要理解互联网的变化轨迹,唯一的方法是弄清背后的规律。“在线”这个所有人既熟悉又陌生的词语,既是常识,也是我一系列想法的核心。
  • 原文地址:https://www.cnblogs.com/JSL2018/p/5936890.html
Copyright © 2011-2022 走看看