#656 (Div. 3)E. Directing Edges(拓扑序列)

题目描述

You are given a graph consisting of n vertices and m edges. It is not guaranteed that the given graph is connected. Some edges are already directed and you can’t change their direction. Other edges are undirected and you have to choose some direction for all these edges.
You have to direct undirected edges in such a way that the resulting graph is directed and acyclic (i.e. the graph with all edges directed and having no directed cycles). Note that you have to direct all undirected edges.
You have to answer t independent test cases.

Input

The first line of the input contains one integer t (1≤t≤2⋅104) — the number of test cases. Then t test cases follow.
The first line of the test case contains two integers n and m (2≤n≤2⋅105, 1≤m≤min(2⋅105,n(n−1)2)) — the number of vertices and the number of edges in the graph, respectively.
The next m lines describe edges of the graph. The i-th edge is described with three integers ti, xi and yi (ti∈[0;1], 1≤xi,yi≤n) — the type of the edge (ti=0 if the edge is undirected and ti=1 if the edge is directed) and vertices this edge connects (the undirected edge connects vertices xi and yi and directed edge is going from the vertex xi to the vertex yi). It is guaranteed that the graph do not contain self-loops (i.e. edges from the vertex to itself) and multiple edges (i.e. for each pair (xi,yi) there are no other pairs (xi,yi) or (yi,xi)).
It is guaranteed that both sum n and sum m do not exceed 2⋅105 (∑n≤2⋅105; ∑m≤2⋅105).

Output

For each test case print the answer — “NO” if it is impossible to direct undirected edges in such a way that the resulting graph is directed and acyclic, otherwise print “YES” on the first line and m lines describing edges of the resulted directed acyclic graph (in any order). Note that you cannot change the direction of the already directed edges. If there are several answers, you can print any.

Example

input
4
3 1
0 1 3
5 5
0 2 1
1 1 5
1 5 4
0 5 2
1 3 5
4 5
1 1 2
0 4 3
1 3 1
0 2 3
1 2 4
4 5
1 4 1
1 1 3
0 1 2
1 2 4
1 3 2
output
YES
3 1
YES
2 1
1 5
5 4
2 5
3 5
YES
1 2
3 4
3 1
3 2
2 4
NO

Note

Explanation of the second test case of the example:
在这里插入图片描述
Explanation of the third test case of the example:
在这里插入图片描述

题目大意

给你一个图,包含n个点和m条边,这m条边中有一些是有向边还有一些是无向边,我们要把这些无向边变为有向边,问能否使得这个图中不包含环。如果可以,则输出所有边的方向。

题目分析

这个题我们可以发现:如果给出的有向边不能组成一个环的话,那么剩下的这些无向边通过指定方向之后一定不会再组成一个环了(即:不会出现某一条无向边不管指定为那个方向都会构成一个环,除非原来的这些有向边就已经组成了一个环)。
因此我们可以先只用有向边来见图,然后用拓扑排序来检查这些有向边组成的图中是否含有环。若有环即为NO,否则就是YES。
然后给无向边加方向只需要按照拓扑序顺序加方向即能保证不会出现环。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <iomanip>
#define LL long long
#define PII pair<int,int>
using namespace std;
const int N=2e5+5;
int n,m; 
int u[N],v[N],st[N];	//st[]记录所有点的入度
vector<int> h[N];
int cnt[N],k=0;		//记录拓扑序
queue<int> q;
void topsort()		//拓扑排序
{
	for(int i=1;i<=n;i++)
		if(!st[i]) q.push(i);
	while(q.size())
	{
		int u=q.front();
		q.pop();
		cnt[u]=++k;		//记录每个点的拓扑序为多少
		for(int it:h[u])
		{
			st[it]--;
			if(!st[it]) q.push(it);
		}
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d %d",&n,&m);
		k=0;
		for(int i=1;i<=m;i++)
		{
			int temp;
			scanf("%d %d %d",&temp,&u[i],&v[i]);
			if(temp)			//如果为有向边,则放入图中
			{
				st[v[i]]++;		//点v[i]的入度加1
				h[u[i]].push_back(v[i]);
			}
		}
		topsort();
		if(n>k) puts("NO");		//n>k说明图中有环
		else
		{
			puts("YES");
			for(int i=1;i<=m;i++)		//根据拓扑序来建边
				if(cnt[u[i]]<cnt[v[i]]) printf("%d %d\n",u[i],v[i]);
				else printf("%d %d\n",v[i],u[i]);
		}
		for(int i=1;i<=n;i++)		//清空数组
		{
			cnt[i]=st[i]=0;
			h[i].clear();
		}
	}
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值