题目大意
题目大意
给定一个 \(n\) 个点和 \(m\) 条边的有向图,并给定 \(p_1, p_2, \cdots, p_n\) 表示第 \(i\) 个点的拓扑序必须小于等于 \(p_i\),求出每个点的最小拓扑序。
题解
题解
题目要求拓扑序尽量小,转换一下就是在反图上拓扑序尽量大。考虑拓扑排序,当一个点不得不入队时,才将它入队,这显然是最优的。
考虑不得不入队的点的情况:
- 再不入队,其他人无法满足 \(p_i\) 的 要求。
- 不入队,后面的点无法进队。
于是用堆模拟这一过程即可。
code:
#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) << ' ';
}