[Luogu1155] [NOIP2008] 雙棧排序 [黑白染色]
阿新 • • 發佈:2018-12-13
題意:給一個到的排列。 判斷能否通過以下四種操作按順序輸出到,並輸出字典序最小的操作序列。 操作分,分別為將第一個元素壓入、彈出棧,壓入、彈出棧 元素被彈出棧時算作輸出。
,複雜度上限基本了
很顯然數字可以被分為壓入棧和棧的,記為黑白二色 都知道一個棧的時候,有如果 那麼無解 可以轉化為如果那麼不能在同一個棧 給連上邊代表不能同色。 判斷有解黑白染色即可。字典序最小所以從開始染,給開始染的點染棧的色 然後模擬兩個棧就好了。 來自於判斷不能同色
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<ctime>
#include<stack>
using namespace std;
#define add_edge(a,b) nxt[++tot]=head[a],head[a]=tot,to[tot]=b
int n,ai[1005]={}, col[1005]={},mn[1005]={},tot=0;
int head[1005]={},nxt[1000005]={},to[1000005]={};
void dfs(int x,int fa)
{
for(int i=head[x];i;i=nxt[i])
{
if(to[i]==fa)continue;
if(!col[to[i]])col[to[i]]=col[x]^3,dfs(to[i],x);
if(col[to[i]]==col[x])
{
printf("0");
exit(0);
}
}
}
stack<int>sa,sb;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&ai[i]);
mn[n]=ai[n];
for(int i=n-1;i;--i)mn[i]=min(mn[i+1],ai[i]);
for(int i=1;i<n-1;++i)
{
for(int j=i+1;j<n;++j)
{
if(mn[j+1]<ai[i]&&ai[i]<ai[j])add_edge(i,j),add_edge(j,i);
}
}
for(int i=1;i<=n;++i)if(!col[i])col[i]=1,dfs(i,0);
int cnt=1;
for(int i=1;i<=n;++i)
{
if(col[i]==1)sa.push(ai[i]),printf("a ");
else sb.push(ai[i]),printf("c ");
while((!sa.empty()&&sa.top()==cnt)||(!sb.empty()&&sb.top()==cnt))
{
if(!sa.empty()&&sa.top()==cnt)sa.pop(),printf("b ");
else sb.pop(),printf("d ");
++cnt;
}
}
return 0;
}