Codeforces 1765H 题解

题目大意

给定一个 \(n\) 个点和 \(m\) 条边的有向图,并给定 \(p_1, p_2, \cdots, p_n\) 表示第 \(i\) 个点的拓扑序必须小于等于 \(p_i\),求出每个点的最小拓扑序。

题解

题目要求拓扑序尽量小,转换一下就是在反图上拓扑序尽量大。考虑拓扑排序,当一个点不得不入队时,才将它入队,这显然是最优的。

考虑不得不入队的点的情况:

  1. 再不入队,其他人无法满足 \(p_i\) 的 要求。
  2. 不入队,后面的点无法进队。

于是用堆模拟这一过程即可。

代码
#include <bits/stdc++.h>

using namespace std;

const int N = 2e3 + 5;
int in[N], n, m, p[N]; vector <int> G[N];
vector <int> ans;

int topo(int x) {
  priority_queue <pair <int, int> > q;
  for (int i = 1; i <= n; ++i) in[i] = 0;
  for (int i = 1; i <= n; ++i) for (auto j : G[i])
    ++in[j];
  for (int i = 1; i <= n; ++i) if (!in[i]) q.emplace(make_pair(p[i], i));
  int now = n;
  while (!q.empty()) {
    int u = q.top().second, P = q.top().first; q.pop();
    if (P < now || u == x) continue;
    ans[now--] = u;
    for (auto v : G[u])
      if (!--in[v]) q.emplace(make_pair(p[v], v));
  } return now;
}

signed main(void) {
  ios :: sync_with_stdio(false);
  cin.tie(nullptr); cout.tie(nullptr);
  cin >> n >> m; ans.assign(n + 1, 0);
  for (int i = 1; i <= n; ++i) cin >> p[i];
  for (int i = 1; i <= m; ++i) {
    int u, v; cin >> u >> v;
    G[v].emplace_back(u);
  }
  for (int i = 1; i <= n; ++i) cout << topo(i) << ' ';
}
posted @ 2023-10-02 11:35  CTHOOH  阅读(18)  评论(0)    收藏  举报