zoukankan      html  css  js  c++  java
  • 双栈排序(二分图

    # 题意
    通过两个栈,4中操作,实现输入序列升序排序
    操作a:如果输入序列不为空,将第一个元素压入栈S1
    操作b:如果栈S1不为空,将S1栈顶元素弹出至输出序列
    操作c:如果输入序列不为空,将第一个元素压入栈S2
    操作d:如果栈S2不为空,将S2栈顶元素弹出至输出序列
    如果一个1~n的排列P可以通过一系列操作使得输出序列为
    1, 2,…,(n-1), n,Tom就称P是一个”可双栈排序排列”。

    操作序列为<a,c,c,b,a,d,d,b>
    另一个可行的序列为<a,c,c,b,a,d,d,b>
    如果序列可双栈排序,输出字典序最小的操作
    否则输出数字0

    # 题解

    如果只有一个栈,则整个操作顺序是固定的:

    从前往后遍历每个数,每次先将当前数压入栈中,如果后面的所有数均比栈顶元素大,则将栈顶弹出,否则栈顶不能被弹出。
    因此,我们只需考虑将每个数分配给哪个栈即可。

    这里有个很强的性质:

    两个数 i , j ( i ≤ j ) 不能被放入同一个栈中,当且仅当存在 k , k > j 且 q [k] < q [i] < q [j]。

    性质证明:
    必要性:
    如果有 i < j < k, 且 q[k] < q[i] < q[j],则因为 q[i] 和 q[j] 的后面均存在一个更小的q[k],因此q[i]和q[j]都不能从栈中被弹出,所以从栈底到栈顶的元素就不是单调的降序了,那么弹出时得到的序列就会出现逆序对。因此q[i]和q[j]不能被分到同一个栈中。
    充分性:
    如果q[i]和q[j]不满足上述条件,则我们在操作过程中一定不会出现矛盾。

    在操作过程中,如果当前要入栈的数是q[j],那么此时:

    所有大于q[j]的元素,都一定在栈中;
    所有小于q[j]的元素,比如q[i] < q[j],则由于后面不存在q[k] < q[i],因此q[i]一定已经出栈;
    所以此时将q[j]压入栈中后,从栈底到栈顶仍然可以保持降序,因此整个进栈、出栈过程是可以顺利进行的。

    有了上述性质后,我们只需将所有满足条件的点分到两个栈中去即可。这一步可以转化成图论问题:

    如果i, j满足条件,则在i和j之间连一条边。
    然后判断是否是二分图即可。

    答案要求字典序最小,因此从前往后染色时,需要优先将当前点分配到第一个栈中。

    时间复杂度
    建图时需要枚举所有点对,时间复杂度是O(n2)。
    染色法判定二分图的时间复杂度是 O(n+m)。
    最后模拟栈排序的过程需要 O(n) 的计算量。

    因此总时间复杂度是 O(n2)。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N=1010;
     4 int n;
     5 int a[N];
     6 int f[N];
     7 int color[N];
     8 bool g[N][N];
     9 stack<int>stk1,stk2;
    10 bool dfs(int u,int c){
    11    color[u]=c;
    12    for(int i=1;i<=n;i++){
    13       if(g[u][i]){
    14          if(color[i] == c)
    15             return 0;
    16          if(color[i] == -1 && !dfs(i,!c)) return 0;
    17       }
    18    }
    19    return 1;
    20 }
    21 int main(){
    22    ios::sync_with_stdio(0);
    23    cin.tie(0);
    24    cout.tie(0);
    25    cin>>n;
    26    memset(g,0,sizeof g);
    27    for(int i=1;i<=n;i++)
    28       cin>>a[i];
    29    f[n+1]=n+1;
    30    for(int i=n;i>=1;i--)
    31       f[i]=min(f[i+1],a[i]);
    32 
    33    for(int i=1;i<=n;i++)
    34       for(int j=i+1;j<=n;j++)
    35          if(a[i] < a[j] && f[j+1] < a[i])
    36             g[i][j]=g[j][i]=1;
    37    memset(color,-1,sizeof color);
    38    for(int i=1;i<=n;i++)
    39       if(color[i]==-1 && !dfs(i,0)){
    40          cout<<0<<endl;
    41          return 0;
    42       }
    43    int now = 1;
    44    for(int i = 1; i<=n;i++){
    45       if(color[i]==0) {
    46          stk1.push(a[i]);
    47          cout<<'a'<<' ';
    48       }
    49       else {
    50          stk2.push(a[i]);
    51          cout<<'c'<<' ';
    52       }
    53 
    54       while(1){
    55          if(stk1.size() && stk1.top()==now){
    56             cout<<'b'<<' ';
    57             stk1.pop();
    58             now++;
    59          }
    60          else if(stk2.size() && stk2.top()==now){
    61             cout<<'d'<<' ';
    62             stk2.pop();
    63             now++;
    64          }
    65          else break;
    66       }
    67    }
    68    cout<<endl;
    69 }
  • 相关阅读:
    WPF 修改Webbrowser的IE版本小程序(32位)
    AnyCAD OpenSource 版本下载和编译
    请求ajax失败的原因(进入到error)
    如何将多个数据的- 转为:来匹配josn格式
    jQuery ajax如何传多个值到后台页面,举例:
    java finalize方法总结、GC执行finalize的过程
    SQL Server索引碎片整理实际操作记录
    MYSQL手册
    Eclipse显示行号
    MyEclipse设置Console输出到文件
  • 原文地址:https://www.cnblogs.com/hhyx/p/12495698.html
Copyright © 2011-2022 走看看