1. 程式人生 > >雙棧排序(二分圖染色+模擬)

雙棧排序(二分圖染色+模擬)

add bool 棧排序 void 不能 div color png turn

題目鏈接 https://www.luogu.org/problemnew/show/P1155

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

一開始我還以為能直接模擬=-=,太天真了...寫了好久對了3個點...看了題解之後恍然大悟,先二分圖匹配一下確定每個點在哪個棧裏頭再模擬會輕松很多。可怎麽建邊呢?

我們先從單棧排序開始:

可以的出的是,對於i,j,若存在k使得i<j<k,且A[k]<A[i]<A[j]的時候,是一定不能單棧排序的

就像3 4 1這樣的數,因為要保證小的先出來,

我們可以在這樣的i,j間建邊,用f[i]存i之後最小的數,這樣就可以把復雜度降到n的平方

之後就可以二分圖染色了=-=,染色時要註意1-n不一定時聯通的,所以要for一遍把所有都染掉

然後就是模擬了=-=字典序有點惡心,但只要時刻保證先出來在進去,先考慮s1,再考慮s2就可以了

代碼:

#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cstring>
using namespace std;
const int N=1010;
int f[N],A[N];
struct node{
    int nu,ne;
}edge[N*N];
int tot,n;
int col[N],head[N],belong[N];
char ans[N*2]; bool vis[N]; void add(int a,int b) { edge[++tot].nu=b; edge[tot].ne=head[a]; head[a]=tot; } bool bfs(int st) { queue<int>q; q.push(st); col[st]=1; vis[st]=true; while(!q.empty()) { int a=q.front(); q.pop();
for(int i=head[a];i!=-1;i=edge[i].ne) { int k=edge[i].nu; if(col[k]==col[a])return false; if(vis[k]) continue; vis[k]=true; col[k]=col[a]==1?2:1; q.push(k); } } return true; } int main() { memset(head,-1,sizeof(head)); stack<int>s1,s2; int bj=1,cnt=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&A[i]); memset(f,0x3f,sizeof(f)); A[n+1]=1e7; 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[j]>A[i]&&A[i]>f[j+1]) add(A[i],A[j]),add(A[j],A[i]); for(int i=1;i<=n;i++) if(!col[A[i]]) if(!bfs(A[i])) return printf("0\n"),0; for(int i=1;i<=n;i++) { if(col[A[i]]==1) belong[A[i]]=1; if(col[A[i]]==2) belong[A[i]]=2; } for(int i=1;i<=n;i++) { int a=belong[A[i]]; while(!s1.empty()&&s1.top()==bj) { bj++; s1.pop(); ans[++cnt]=b; } while(!s2.empty()&&s2.top()==bj) { bj++; s2.pop(); ans[++cnt]=d; } if(a==1) { s1.push(A[i]); ans[++cnt]=a; } if(a==2) { s2.push(A[i]); ans[++cnt]=c; } } while(!s1.empty()&&!s2.empty()) { if(s1.top()<s2.top()) { s1.pop(); ans[++cnt]=b; } else { s2.pop(); ans[++cnt]=d; } } while(!s1.empty())s1.pop(),ans[++cnt]=b; while(!s2.empty())s2.pop(),ans[++cnt]=d; for(int i=1;i<=cnt;i++) printf("%c ",ans[i]); return 0; }

雙棧排序(二分圖染色+模擬)