P1155 双栈排序(二分图+栈)

题意:传送门
题解:首先考虑样例怎么做 1 , 3 , 2 , 4 1, 3, 2, 4 1,3,2,4,先把 1 1 1压入栈 1 1 1,然后弹出,接着把 3 3 3压进去,把 2 2 2再压进去,把 2 2 2弹出来,把 3 3 3弹出来,再把 4 4 4压进去,这样利用一个栈就可以实现,并且是字典序最小,那么何时需要两个栈呢?再随便搞组样例试试, 2 2 2, 3 3 3, 1 1 1,发现什么啦,发现 1 1 1弹出后,这个 2 2 2按理说要比 3 3 3先弹出来,但是被卡住了,所以在需要来个栈帮忙下,这其实是一个性质,就是一个序列中,两个位置(比如 i i i j j j)要是能放入一个栈操作的话,必然不能满足 a [ k ] &lt; a [ i ] &lt; a [ j ] , i &lt; j &lt; k a[k]&lt;a[i]&lt;a[j],i&lt;j&lt;k a[k]<a[i]<a[j]i<j<k,这也是个充分必要条件,这样必然会卡住前面的数出不来,所以可以将这样的数通过二分图连接起来,白色的用一个栈,黑色用用一个栈,如果不满足二分图,说明可能要用超过 2 2 2个栈,那样输出 0 0 0即可, 接着考虑如何字典序最小,栈一操作最小,可以将二分图先染为白色,然后再染为黑色,白色的就用 1 1 1栈,黑色的用 2 2 2栈,然后就用栈模拟输出就完全可以了。
c o d e : code: code:

#include<bits/stdc++.h>
using namespace std;
const int N=1000+10;
int T,n,a[N],f[N],g[N][N],color[N];
stack<int>stk1,stk2;
bool dfs(int u,int c)
{
    color[u]=c;
    for(int i=1;i<=n;i++){
        if(g[u][i]){
            if(color[i]==c)return false;
            if(color[i]==-1&&!dfs(i,!c))return false;
        }
    }
    return true;
}
int main()
{
       cin>>n;
       for(int i=1;i<=n;i++)cin>>a[i];
       f[n+1]=N;
       for(int i=n;i>=1;i--)f[i]=min(f[i+1],a[i]);
       memset(g,false,sizeof g);
       for(int i=1;i<n;i++){
           for(int j=i+1;j<=n;j++){
               if(a[i]<a[j]&&f[j+1]<a[i])g[i][j]=g[j][i]=true;
           }
       }
       memset(color,-1,sizeof color);
       bool flag=true;
       for(int i=1;i<=n;i++){
           if(color[i]==-1&&!dfs(i,0))flag=false;
       }
       if(!flag){
           cout<<0<<endl;
       }else{
           int now=1;
           for(int i=1;i<=n;i++){
               if(color[i]==0){
                   stk1.push(a[i]);
                   cout<<"a"<<" ";
               }else{
                   stk2.push(a[i]);
                   cout<<"c"<<" ";
               }
               while(233){
                   if(stk1.size()&&stk1.top()==now){
                       stk1.pop();
                       cout<<"b"<<" ";
                       now++;
                   }else if(stk2.size()&&stk2.top()==now){
                       stk2.pop();
                       cout<<"d"<<" ";
                       now++;
                   }else{
                       break;
                   }
               }
           }
           cout<<endl;
       }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值