算法刷题笔记(一)(1) Acwing.153. 双栈排序

Solution

https://www.acwing.com/problem/content/155/

二分图,染色,贪心 O(n^2)

性质

当且仅当i < j < k, q[k] < q[i] < q[j] 的情况下, 两个数无法放到同一栈中


证明

充分性:
假设i < j < k, q[k] < q[i] < q[j] 的情况下, 可以放到一个栈中
那么则因为 q[i] 和 q[j] 的后面均存在一个更小的q[k],因此q[i]和q[j]都不能从栈中被弹出,所以从栈底到栈顶的元素就不是单调的降序了, 即不能放到一个栈中,即出现矛盾。

必要性
即:如果无法放到同一栈中 那么这俩数一定满足上述条件
反证
如果i,j不能进入同一个栈,且不存在 i < j < k 使
a[j]>a[i]>a[k]
那么j和j之后的元素一定在i之后出栈,所以当序列遍历到j时,一定可以让i出栈,进而j就可以进栈了。即出现矛盾


证毕。

根据此性质可以找到哪些数不能在进入一个栈中,给不能进入同一个栈的数连边
利用染色法划分二分图,不是二分图输出0,是二分图根据划分的栈模拟找到答案。

保证字典序最小
操作优先按a b c d输出
注意不要按stk1 stk2去考虑字典序

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>

using namespace std;

const int N = 1010;

int n;
int q[N], f[N]; //f[i] i ~ 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()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &q[i]);
    f[n + 1] = n + 1;
    memset(g, false, sizeof g);
    for (int i = n; i; i -- ) f[i] = min(f[i + 1], q[i]);
    
    for (int i = 1; i <= n; i ++ )
        for (int j = i + 1; j <= n; j ++ )
            if (f[j + 1] < q[i] && q[i] < q[j])
                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)
    {
        printf("0\n");
        return 0;
    }
    stack<int> stk1, stk2;
    
    int now = 1;
    int j = 1;
     for(int i = 1; i <= 2 * n; i++)
     {
        if(j <= n && !color[j] && (!stk1.size() || stk1.size() && stk1.top() > q[j]))
        {
            stk1.push(q[j]);
            j ++ ;
            cout << "a ";
        }
        else if(stk1.size() && stk1.top() == now)
        {
            stk1.pop();
            cout << "b ";
            now ++ ;
        }
        else if(j <= n && color[j] && (!stk2.size() || stk2.size() && stk2.top() > q[j]))
        {
            stk2.push(q[j]);
            j ++ ;
            cout << "c ";
        }
        else if(stk2.size() && stk2.top() == now)
        {
            stk2.pop();
            cout << "d ";
            now ++ ;
        }
    }
    return 0;
}
posted @ 2023-06-23 18:38  hhhhhua  阅读(83)  评论(0)    收藏  举报