算法知识点: 二分图,栈,染色法,贪心
复杂度:
解题思路:
如果只有一个栈,则整个操作顺序是固定的:
- 从前往后遍历每个数,每次先将当前数压入栈中,如果后面的所有数均比栈顶元素大,则将栈顶弹出,否则栈顶不能被弹出。
因此,我们只需考虑将每个数分配给哪个栈即可。
这里有个很强的性质:
两个数
不能被放入同一个栈中,当且仅当存在
且
。
有了上述性质后,我们只需将所有满足条件的点分到两个栈中去即可。这一步可以转化成图论问题:
- 如果i, j满足条件,则在i和j之间连一条边。
然后判断是否是二分图即可。
答案要求字典序最小,因此从前往后染色时,需要优先将当前点分配到第一个栈中。
C++ 代码:
#include <iostream>
#include <algorithm>
#include <stack>
#include <cstring>
using namespace std; const int N = 1010;
int n;
int a[N], f[N];
int color[N];
bool g[N][N];
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 false;
if (color[i] == -1 && !dfs(i, !c)) return false;
}
return true;
}
int main()
{
int T;
cin >> T;
while (T--)
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
f[n + 1] = n + 1;
memset(g, false, sizeof g);
for (int i = n; i; 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] = true;
memset(color, -1, sizeof color);
bool flag = true;
for (int i = 1; i <= n; i++)
if (color[i] == -1 && !dfs(i, 0))
{
flag = false;
break;
}
if (!flag)
{
cout << 0 << endl;
continue;
}
stack<int> stk1, stk2;
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 (true)
if (stk1.size() && stk1.top() == now)
{
stk1.pop();
cout << "b ";
now++;
}
else if (stk2.size() && stk2.top() == now)
{
stk2.pop();
cout << "d ";
now++;
}
else break;
}
cout << endl;
}
return 0;
} 
京公网安备 11010502036488号