1. 程式人生 > 實用技巧 >【二分圖匹配】 雙棧排序

【二分圖匹配】 雙棧排序

題意

通過兩個棧,4中操作,實現輸入序列升序排序

  • \(操作a:如果輸入序列不為空,將第一個元素壓入棧S_{1}\)
  • \(操作b:如果棧S_{1}不為空,將S_{1}棧頂元素彈出至輸出序列\)
  • \(操作c:如果輸入序列不為空,將第一個元素壓入棧S_{2}\)
  • \(操作d:如果棧S_{2}不為空,將S_{2}棧頂元素彈出至輸出序列\)

如果一個\(1\sim n\)的排列\(P\)可以通過一系列操作使得輸出序列為
\(1, 2,\sim,(n-1), n\),就稱P是一個”可雙棧排序排列”。

操作序列為\(<a,c,c,b,a,d,d,b>\)
另一個可行的序列為\(<a,c,c,b,a,d,d,b>\)


如果序列可雙棧排序,輸出字典序最小的操作
否則輸出數字\(0\)

資料範圍

\(1 \leq n \leq 1000\)

題解

Code

cpp

#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n;
int a[N];
int f[N];
int color[N];
bool g[N][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 0;
         if(color[i] == -1 && !dfs(i,!c)) return 0;
      }
   }
   return 1;
}
int main(){
   ios::sync_with_stdio(0);
   cin.tie(0);
   cout.tie(0);
   cin>>n;
   memset(g,0,sizeof g);
   for(int i=1;i<=n;i++)
      cin>>a[i];
   f[n+1]=n+1;
   for(int i=n;i>=1;i--)
      f[i]=min(f[i+1],a[i]);

   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]=1;
   memset(color,-1,sizeof color);
   for(int i=1;i<=n;i++)
      if(color[i]==-1 && !dfs(i,0)){
         cout<<0<<endl;
         return 0;
      }
   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(1){
         if(stk1.size() && stk1.top()==now){
            cout<<'b'<<' ';
            stk1.pop();
            now++;
         }
         else if(stk2.size() && stk2.top()==now){
            cout<<'d'<<' ';
            stk2.pop();
            now++;
         }
         else break;
      }
   }
   cout<<endl;
}