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 也许就可达了。

这样直接写肯定不行,所以我们需要一些剪枝(对于s1s2 都能放的情况)。

  1. 如果 s1 是空的,并且 s2 也是,那么放两个栈都是一样的,若 s1 不行,s2 也肯定不行,故只放 s1.
  2. 如果 s1 是空的,并且 s2 不是,没有优化,只能两个都试。
  3. 如果 s1 不是空的,并且 s2 是空的,只放 s1 ,(因为放 s1 的方案都能包容 s2 的,并且字典序更小)。
  4. 如果 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!.

posted @ 2020-11-28 21:23  cjlworld  阅读(117)  评论(0编辑  收藏  举报