AcWing 153. 双栈排序 震惊 !2^n 过 1000
感觉有点标题党,不过我的代码确实过了qwq。
题目描述
可见: https://www.acwing.com/problem/content/155/
样例
Input:
4
1 3 2 4
Output:
a b a a b b a b
算法:暴力100pts
当然还是需要一点剪枝的呀,QAQ.
我们可以从题目中提取出以下几条性质:
- 每个栈内上面的数字必须比他小。
- 要等到当前数字是待输入序列和栈内元素的最小才能弹出。(这个可以用堆)
- 优先放栈1。(为保证字典序最小)
思路: (以下用s1
表示stack1
,s2
表示stack2
)
- s1 能放 等价于
s1.empty()||s1.top()>a[u]
; - s1 同理
- 如果两个栈都不能放,
return false;
- 如果
s1
能放并且s2
不能放,别无选择,放s1
. - 如果
s2
能放并且s1
不能放,别无选择,放s2
. - 如果
s1
,s2
都能放,注意了,不是只放s1
而不放s2
了,
因为如果s1.top()
更大一些,或者其他一些情况,会导致可能不可达,但放s2
也许就可达了。
这样直接写肯定不行,所以我们需要一些剪枝(对于s1
,s2
都能放的情况)。
- 如果
s1
是空的,并且s2
也是,那么放两个栈都是一样的,若s1
不行,s2
也肯定不行,故只放s1
. - 如果
s1
是空的,并且s2
不是,没有优化,只能两个都试。 - 如果
s1
不是空的,并且s2
是空的,只放s1
,(因为放s1
的方案都能包容s2
的,并且字典序更小)。 - 如果
s1
不是空的,并且s2
不是空的- 若
s1.top()<s2.top()
, 只放s1
,证明同3. - 若
s1.top()>s2.top()
,没有优化,只能两个都试。
- 若
至此我们可以写出代码。
Code:
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1e4+5;
char path[N];
int n;
int a[N];
int tot=0;
int s1[N],s2[N],t1,t2;
priority_queue<int,vector<int>,greater<int> > q;
bool dfs(int u);
inline bool c1(int u)
{
vector<int> v1,v2;
s1[++t1]=a[u];
path[++tot]='a';
while(s2[t2]==q.top()||s1[t1]==q.top()) {
if(s2[t2]==q.top()) {
v2.push_back(s2[t2]);
q.pop();
t2--;
path[++tot]='d';
}
else {
v1.push_back(s1[t1]);
q.pop();
t1--;
path[++tot]='b';
}
}
if(dfs(u+1)) return true;
if(v1.size()||v2.size()) {
while(v1.size()) s1[++t1]=v1.back(),q.push(v1.back()),v1.pop_back(),tot--;
while(v2.size()) s2[++t2]=v2.back(),q.push(v2.back()),v2.pop_back(),tot--;
}
tot--;
t1--;
return false;
}
inline bool c2(int u)
{
vector<int> v1,v2;
s2[++t2]=a[u];
path[++tot]='c';
while(s2[t2]==q.top()||s1[t1]==q.top()) {
if(s2[t2]==q.top()) {
v2.push_back(s2[t2]);
q.pop();
t2--;
path[++tot]='d';
}
else {
v1.push_back(s1[t1]);
q.pop();
t1--;
path[++tot]='b';
}
}
if(dfs(u+1)) return true;
if(v1.size()||v2.size()) {
while(v1.size()) s1[++t1]=v1.back(),q.push(v1.back()),v1.pop_back(),tot--;
while(v2.size()) s2[++t2]=v2.back(),q.push(v2.back()),v2.pop_back(),tot--;
}
tot--;
t2--;
return false;
}
bool dfs(int u)
{
if(u==n+1) return true;
int k1=(t1==0||a[u]<s1[t1]),k2=(t2==0||(a[u]<s2[t2]));
if(!k1&&!k2) return false;
else if((k1&&!k2)||(k1&&t2==0)||(t1>0&&t2>0&&s1[t1]<s2[t2]&&k1)) {
if(c1(u)) return true;
}
else if(k2&&!k1) {
if(c2(u)) return true;
}
else {
if(c1(u)) return true;
if(c2(u)) return true;
}
// if(k1&&c1(u)) return true;
// if(k2&&c2(u)) return true;
return false;
}
int main()
{
// freopen("1.in","r",stdin);
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]),q.push(i);
if(!dfs(1)) printf("0\n");
else {
for(i=1;i<=tot;i++)
printf("%c ",path[i]);
printf("\n");
}
return 0;
}
时间复杂度
最坏情况下是 \(O(2^n)\)。
但也能通过本题。
启发
Never give up!
.