P4376题解

我们来看一下这道题:

  1. 求出题目所说的 $X$
  • 二分答案 $X$,对于每个的二分的 $mid$,拓扑排序判断是否行

  • $check$ 部分 :

    1. 一遍拓扑排序

    2. 判断每个节点的入度是否为零,若全为零,$return$ $true$,若又不为零,$return $ $false$

  1. 再求出最佳顺序
  • 拓扑排序出结果

注意事项:

  1. 在每次拓扑排序中都要新建图,记得清空

  2. 求出最佳顺序的那次拓扑排序要使用优先队列 (毕竟题目要字典序小的靠前)

具体实现可以借助代码理解:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int maxn = 100010;
struct node {
    int to, nxt;
} edge[maxn << 1];
struct Node {
    int u, v;
} p[maxn << 1];
int n, m, cnt, d[maxn], num[maxn], head[maxn];
queue <int> q;
priority_queue <int, vector<int>, greater<int> > pq;

void add (int u, int v) {
    cnt ++;
    edge[cnt].to = v;
    edge[cnt].nxt = head[u];
    head[u] = cnt;
}

bool check (int x) {
    cnt = 0;
    memset (d, 0, sizeof (d));
    memset (head, 0, sizeof (head));
    for (int i = 1; i <= num[x]; ++i) {
        add (p[i].u, p[i].v);
        d[p[i].v] ++;
    }
    for (int i = 1; i <= n; ++i) {
        if (!d[i]) q.push (i);
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].to;
            d[v] --;
            if (!d[v]) q.push (v);
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (d[i]) return false;
    }
    return true;
}

void query (int x) {
    cnt = 0;
    memset (d, 0, sizeof (d));
    memset (head, 0, sizeof (head));
    for (int i = 1; i <= num[x]; ++i) {
        add (p[i].u, p[i].v);
        d[p[i].v] ++;
    }
    for (int i = 1; i <= n; ++i) {
        if (!d[i]) pq.push (i);
    }
    while (!pq.empty()) {
        int u = pq.top();
        pq.pop();
        printf ("%d ", u);
        for (int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].to;
            d[v] --;
            if (!d[v]) pq.push (v);
        }
    }
}

int main() {
    scanf ("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        int sum; scanf ("%d", &sum);
        int last; scanf ("%d", &last);
        for (int j = 1; j < sum; ++j) {
            int x; scanf ("%d", &x);
            p[num[i - 1] + j] = (Node){last, x};
            last = x;
        }
        num[i] = num[i - 1] + sum - 1;
    }
    int l = 1, r = m;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (check (mid + 1)) l = mid + 1;
        else r = mid;
    }
    query (l);
    return 0;
}
posted @ 2021-06-01 16:55  wangzhongyuan  阅读(2)  评论(0编辑  收藏  举报  来源