2021牛客暑期多校训练营2 K. Stack(拓扑排序)

链接:https://ac.nowcoder.com/acm/contest/11253/K
来源:牛客网

题目描述

ZYT had a magic permutation a1,a2,⋯ ,ana1,a2,⋯,an, and he constructed a sequence b1,b2,⋯bnb1,b2,⋯bn by the following pseudo code:

Stk is an empty stack for i = 1 to n : while ( Stk is not empty ) and ( Stk's top > a[i] ) : pop Stk push a[i] b[i]=Stk's sizeBut he somehow forgot the permutation aa, and only got some kk elements of bibi.

Construct a permutation aa satisfying these bibi , or determine no such permutation exists.

Here a permutation refers to a sequence that contains all integers from 11 to nn exactly once.

输入描述:

The first line contains two integers nn,k(1≤k≤n)k(1≤k≤n) — the length of the permutation, the number of  left bibi.

Then kk lines each contains two integer pi,xipi,xi, denoting that bpi=xibpi=xi.

输出描述:

Output one line with n integers a1,a2,⋯ana1,a2,⋯an — a possible permutation.

If no such permutation exists, output one integer -1.

示例1

输入

复制

5 2
2 2
5 4

输出

复制

1 2 5 3 4

示例2

输入

复制

10 1
1 10

输出

复制

-1

题意就是让你构造出来一个序列a,在a上从i = 1到n跑单调栈的同时使栈的大小在指定位置为特定大小。比赛的时候队友调了4h假算法QAQ

正解就是通过b数组以及题目描述,构建b数组对应位置的a数组的元素的相对关系,然后拓扑排序分配编号即可。首先需要找到一种补全b数组的方法(当然不用真的补全),而要求b[i] <= i,因此令缺失部分的b[i] = b[i - 1] + 1即可满足要求(贪心)。然后i = 1 ~ n遍历每个位置同时模拟单调栈的过程,注意和题目说的不同的是栈中存放的是一个个下标(因为本身要构造的就是a序列,同时b序列已补全,实际上存储的就是a序列的对应下标了,这样可以求出来a序列各个位置之间的数的大小关系)。遍历到一个位置时如果这个位置的b[i]没有初始值,说明在这个位置执行的是入栈操作,把i入栈,这个位置的数大于栈顶那个位置对应的数;如果b[i]有初始值,若栈的大小+1比b[i]小说明无解,如果栈的大小+1等于b[i]则把i直接入栈,这个位置的数大于栈顶那个位置对应的数,若栈的大小比b[i]大则不断弹出栈顶元素并指明栈顶元素对应位置的数大于i这个位置对应的数,最后指明i这个位置的数大于栈顶元素位置对应的数并把i入栈。这样就可以得到一系列的a[i] > a[j]这样的关系(由i指向j的有向边)构成的关系图(显然为DAG),直接跑拓扑排序分配a[i]即可。

注意如果用stl的stack实现的话需要判断栈空的情况,手动模拟的话就很方便。

#include<bits/stdc++.h>
#define N 1000005
#define M 4000005
using namespace std;
int n, k, b[N], a[N];
int head[N], ver[M], Next[M], tot = 0;
int deg[N];
void add(int x, int y) {
    ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
void Toposort() {
    queue<int> q;
    int cnt = n;
    for(int i = 1; i <= n; i++) {
        if(!deg[i]) {
            q.push(i);
        }
    }
    while(q.size()) {
        int now = q.front();
        q.pop();
        a[now] = cnt--;
        for(int i = head[now]; i; i = Next[i]) {
            int y = ver[i];
            deg[y]--;
            if(deg[y] == 0) {
                q.push(y);
            }
        }

    }
}
int main(){
    cin >> n >> k;
    for(int i = 1; i <= k; i++) {
        int p, x;
        cin >> p >> x;
        b[p] = x;
    }
    stack<int> stk;//栈中存放的是一系列位置
    bool ok = 1;
    for(int i = 1; i <= n; i++) {
        //cout << i << endl;
        if(b[i]) {
            if(stk.size() + 1 < b[i]) {
                ok = 0;
                break;
            } else if(stk.size() + 1 == b[i]) {
                if(i != 1) {
                    add(i, stk.top());//a[i]比栈顶对应位置的元素大
                    deg[stk.top()]++;
                }
                stk.push(i);
            } else {
                while(stk.size() + 1 > b[i] && stk.size()) {
                    int now = stk.top();
                    stk.pop();
                    add(now, i);
                    deg[i]++;
                }
                if(stk.size()) {
                    add(i, stk.top());
                    deg[stk.top()]++;
                }
                stk.push(i);
            }
        } else {
            if(i != 1) {
                add(i, stk.top());//a[i]比栈顶对应位置的元素大
                deg[stk.top()]++;
            }
            stk.push(i);
        }
    }
    if(!ok) {
        cout << -1;
        return 0;
    } else {
        Toposort();
        for(int i = 1; i <= n; i++) {
            cout << a[i] << " ";
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lipoicyclic/p/15033783.html