CF-Educational-25 E-Minimal Labels (拓扑排序,字典序)

You are given a directed acyclic graph with n vertices and m edges. There are no self-loops or multiple edges between any pair of vertices. Graph can be disconnected.

You should assign labels to all vertices in such a way that:

  • Labels form a valid permutation of length n — an integer sequence such that each integer from 1 to n appears exactly once in it.
  • If there exists an edge from vertex v to vertex u then labelv should be smaller than labelu.
  • Permutation should be lexicographically smallest among all suitable.

Find such sequence of labels to satisfy all the conditions.

Input

The first line contains two integer numbers nm (2 ≤ n ≤ 105, 1 ≤ m ≤ 105).

Next m lines contain two integer numbers v and u (1 ≤ v, u ≤ n, v ≠ u) — edges of the graph. Edges are directed, graph doesn't contain loops or multiple edges.

Output

Print n numbers — lexicographically smallest correct permutation of labels of vertices.

Examples
input
3 3
1 2
1 3
3 2
output
1 3 2 
input
4 5
3 1
4 1
2 3
3 4
2 4
output
4 1 2 3 
input
5 4
3 1
2 1
2 3
4 5
output
3 1 2 4 5 
此题是拓扑排序裸题,但字典序要注意。取出节点时要先取出编号大的节点打上编号大的标签(反图),如果直接从小到大找入度为零的点然后编号的话会有反例


如图,如果从小到大讨论的话答案是     3    1     2    但显然正解是       2       3       1

附我naive的wa代码

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#define N 2222222
using namespace std;
int n,m,d[N],tot,ans[N];
int TOT,EN[N],NE[N],LA[N];
void ADD(int x,int y)
{
	TOT++;
	EN[TOT]=y;
	NE[TOT]=LA[x];
	LA[x]=TOT;
}
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
	int i,j,x,y;
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		d[y]++;ADD(x,y);
	}
	for(i=1;i<=n;i++)if(d[i]==0)q.push(i);
	while(!q.empty())
	{
		x=q.top();
		q.pop();
		ans[x]=++tot;
		for(i=LA[x];i;i=NE[i])
		{
			y=EN[i];
			if(d[y]>0)
			{
				d[y]--;
			    if(d[y]==0)q.push(y);
			}
		}
		
	}
	for(i=1;i<=n;i++)printf("%d ",ans[i]);
}


附ac代码

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#define N 222222
using namespace std;
int n,m,d[N],tot,ans[N];
int TOT,EN[N],NE[N],LA[N];
void ADD(int x,int y)
{
	TOT++;
	EN[TOT]=y;
	NE[TOT]=LA[x];
	LA[x]=TOT;
}
priority_queue<int>q;
int main()
{
	int i,j,x,y;
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		d[x]++;ADD(y,x);
	}
	for(i=1;i<=n;i++)if(d[i]==0)q.push(i);
	tot=n;
	while(!q.empty())
	{
		x=q.top();
		q.pop();
		ans[x]=tot--;
		for(i=LA[x];i;i=NE[i])
		{
			y=EN[i];
			if(d[y]>0)
			{
				d[y]--;
			    if(d[y]==0)q.push(y);
			}
		}
		
	}
	for(i=1;i<=n;i++)printf("%d ",ans[i]);
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值