题目链接:https://codeforces.com/problemset/problem/825/E
11.1 题意
给出一个 n ( 2 ≤ n ≤ 1 0 5 ) n(2 \le n \le 10^5) n(2≤n≤105) 个节点和 m ( 1 ≤ m ≤ 1 0 5 ) m(1 \le m \le 10^5) m(1≤m≤105) 条边的有向无环图,保证没有自环和重边,但不保证图联通。
现在要给每个点编号,范围为 [ 1 , n ] [1,n] [1,n],并要求每个编号只能使用一次。设点 i i i 的编号为 p i p_i pi,则对于有向边 < u , v > <u,v> <u,v>,必须满足 p u < p v p_u < p_v pu<pv。
显然 p p p 构成一个排列。问满足要求的字典序最小的 p p p。
11.2 解题过程
如果不考虑字典序,则直接进行拓扑排序即可得到一组解。
如果考虑字典序的话,只需将队列换成优先队列即可。
时间复杂度: O ( n log n ) O(n \log n) O(nlogn)。
11.3 代码
int n, m;
int head[maxn], cnt;
int ans[maxn], indeg[maxn];
struct edge
{
int v, nxt;
} Edge[2 * maxn];
void init()
{
for(int i = 0; i <= n; i++) head[i] = -1;
cnt = 0;
}
void addedge(int u, int v)
{
Edge[cnt].v = v;
Edge[cnt].nxt = head[u];
head[u] = cnt++;
indeg[v]++;
}
int flag;
priority_queue<int> que;
void toposort()
{
for(int i = 1; i <= n; i++)
{
if(!indeg[i]) que.push(i);
}
while(!que.empty())
{
int now = que.top();
que.pop();
ans[now] = flag--;
for(int i = head[now]; i != -1; i = Edge[i].nxt)
{
int v = Edge[i].v;
--indeg[v];
if(!indeg[v]) que.push(v);
}
}
}
int main()
{
int u, v;
scanf("%d%d", &n, &m);
init();
flag = n;
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
addedge(v, u);
}
toposort();
for(int i = 1; i <= n; i++)
{
if(i > 1) printf(" ");
printf("%d", ans[i]);
}
return 0;
}