zoukankan      html  css  js  c++  java
  • NOIP2008 双栈队列

    1.      双栈排序

    (twostack.pas/c/cpp)

     

    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 希望知道其中字典序最小的操作序列是什么。

    【输入】

    输入文件 twostack.in 的第一行是一个整数 n。

    第二行有 n 个用空格隔开的正整数,构成一个 1~n 的排列。

     

    【输出】

    输出文件 twostack.out 共一行,如果输入的排列不是“可双栈排序排列”,输出数字 0;

    否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。

     

    【输入输出样例1】

    twostack.in

    twostack.out

    4

    1 3 2 4

    a b a a b b a b

     

    【输入输出样例2】

    twostack.in

    twostack.out

    4

    2 3 4 1

    0

     

    【输入输出样例3】

    twostack.in

    twostack.out

    3

    2 3 1

    a c a b b d

     

    【限制】

    30%的数据满足: n<=10

    50%的数据满足: n<=50

    100%的数据满足: n<=1000

    【思路】

       构造“不可能”边+二分图着色

       点的分配转化为了二分图的着色。

     

    (以下摘自洛谷OI【题解】)

     考虑对于任意两个数q1[i]和q1[j]来说,它们不能压入同一个栈中的充要条件是什么(注意没有必要使它们同时存在于同一个栈中,只是压入了同一个 栈).实际上,这个条件p是:存在一个k,使得i<j<k且q1[k]<q1[i]<q1[j].

    首先证明充分性,即如果满足条件p,那么这两个数一定不能压入同一个栈.这个结论很显然,使用反证法可证.
    假设这两个数压入了同一个栈,那么在压入q1[k]的时候栈内情况如下:
    …q1[i]…q1[j]…
    因为q1[k]比q1[i]和q1[j]都小,所以很显然,当q1[k]没有被弹出的时候,另外两个数也都不能被弹出(否则q2中的数字顺序就不是1,2,3,…,n了).
    而之后,无论其它的数字在什么时候被弹出,q1[j]总是会在q1[i]之前弹出.而q1[j]>q1[i],这显然是不正确的.

    接下来证明必要性.也就是,如果两个数不可以压入同一个栈,那么它们一定满足条件p.这里我们来证明它的逆否命题,也就是"如果不满足条件p,那么这两个数一定可以压入同一个栈."
    不满足条件p有两种情况:一种是对于任意i<j<k且q1[i]<q1[j],q1[k]>q1[i];另一种是对于任意i<j,q1[i]>q1[j].
    第一种情况下,很显然,在q1[k]被压入栈的时候,q1[i]已经被弹出栈.那么,q1[k]不会对q1[j]产生任何影响(这里可能有点乱,因为看起 来,当q1[j]<q1[k]的时候,是会有影响的,但实际上,这还需要另一个数r,满足j<k<r且 q1[r]<q1[j]<q1[k],也就是证明充分性的时候所说的情况…而事实上我们现在并不考虑这个r,所以说q1[k]对q1[j]没 有影响).
    第二种情况下,我们可以发现这其实就是一个降序序列,所以所有数字都可以压入同一个栈.
    这样,原命题的逆否命题得证,所以原命题得证.

    此时,条件p为q1[i]和q1[j]不能压入同一个栈的充要条件也得证.

    这样,我们对所有的数对(i,j)满足1<=i<j<=n,检查是否存在i<j<k满足p1[k]<p1[i]& lt;p1[j].如果存在,那么在点i和点j之间连一条无向边,表示p1[i]和p1[j]不能压入同一个栈.此时想到了什么?那就是二分图~
    二分图的两部分看作两个栈,因为二分图的同一部分内不会出现任何连边,也就相当于不能压入同一个栈的所有结点都分到了两个栈中.
    此时我们只考虑检查是否有解,所以只要o(n)检查出这个图是不是二分图,就可以得知是否有解.

    然后处理最小字典序问题。实际上对二分图染色后对应的操作显然编号小的优先使用a操作,可以使得字典序尽量小。

    这里要提二分图的一个性质:二分图中不同的连通分量染色是互不影响的。所以为了满足最小字典序的问题,可以选取编号最小的未染色结点染成1并对它所在连通分量染色。染完之后,模拟输出序列就可以了。

     

    【代码】

     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<vector>
     4 #include<stack>
     5 using namespace std;
     6 const int maxn = 1000+10;
     7 
     8 int S[maxn],C[maxn];
     9 vector<int> G[maxn];
    10 int n;
    11 
    12 void dfs(int u,int c){
    13     C[u]=c;
    14     for(int i=0;i<G[u].size();i++){
    15       int v=G[u][i];
    16       if(C[v]==C[u]) {
    17             cout<<0; exit(0);
    18       }
    19       else if(!C[v]) dfs(v,3-c);
    20     }
    21 }
    22 int main() {
    23     ios::sync_with_stdio(false);
    24     
    25     cin>>n;
    26     for(int i=1;i<=n;i++) cin>>S[i];
    27     int _min[maxn]; _min[n+1]=1<<30;
    28     for(int i=n;i;i--) _min[i]=min(_min[i+1],S[i]);
    29     for(int i=1;i<n;i++) 
    30      for(int j=i+1;j<=n;j++) if(S[i]<S[j] && _min[j+1]<S[i]) {  //i<j<k && (S[k]<S[i]<S[j])
    31          G[i].push_back(j); G[j].push_back(i);
    32      }
    33      
    34     for(int i=1;i<=n;i++) if(!C[i])  dfs(i,1);  
    35     
    36     int aim=1;
    37     stack<int> sta,stb;
    38     for(int i=1;i<=n;i++) {
    39         if(C[i]==1) {
    40            sta.push(S[i]); cout<<"a ";
    41         }
    42         else {
    43            stb.push(S[i]); cout<<"c ";
    44         }
    45         while(!sta.empty()&&sta.top()==aim || !stb.empty()&&stb.top()==aim) {
    46             if(!sta.empty()&&sta.top()==aim){
    47                 sta.pop(); cout<<"b ";
    48             }
    49             else {
    50                 stb.pop(); cout<<"d ";
    51             }
    52             aim++;
    53         }
    54     }
    55     return 0;
    56 }
  • 相关阅读:
    Do You See Me? Ethical Considerations of the Homeless
    ELDER HOMELESSNESS WHY IS THIS AN ISSUE?
    Endoflife support is lacking for homeless people
    html内联框架
    html字体
    html块 div span
    html列表
    html表格
    SQL Server管理员专用连接的使用   作为一名DBA,经常会处理一些比较棘手的服务无响应问题,鉴于事态的严重性,多数DBA可能直接用“重启”大法,以便尽快的恢复生产环境的正常运转,但是多数情况
    如何配置最大工作线程数 (SQL Server Management Studio)
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4859436.html
Copyright © 2011-2022 走看看