CF1385E Directing Edges 题解

题目大意

给定一张 \(n\) 个点,\(m\) 条边的图 \(G\),其中一部分边是有向边,一部分边是无向边。需要给所有给无向边定向,使得组成的新图是一个 DAG。

多测,\(T\leq 2\times10^4\)\(\sum n,\sum m\leq 2\times 10^5\)

符号及约定

\(\operatorname{edge}(u,v)\) 表示节点 \(u\)\(v\) 之间的边。\(u\to v\) 表示一条从 \(u\)\(v\) 的有向边。

Solution

先忽视所有无向边。如果剩余的所有有向边不能组成 DAG,那么无论无向边怎么定向也没用。

接下来考虑有向边没有问题时如何构造可行解即可。

不妨对有向边组成的 DAG 进行 topo sort,得到第 \(i\) 个节点的 topo sort 序不妨记为 \(\operatorname{ord}(i)\)

任取一条无向边 \(\operatorname{edge}(u,v)\),不妨令 \(\operatorname{ord}(u)<\operatorname{ord}(v)\)(反正是无向边,并且方向待定,没有区别)。那么直接令 \(\operatorname{edge}(u,v)=u\to v\) 即可。原因是因为 \(\forall u,v\in G'\)(这里 \(G'\) 是一个 DAG)满足 \(\operatorname{ord}(u)<\operatorname{ord}(v)\),则不存在 \(v\to u\) 这条边。

我们不妨形象地将 topo sort 所得的点序排列成一行,从左到右分别为 \(\operatorname{ord}(u)=1,2,3,...,n\) 的节点。那么已经存在的构成 DAG 的边必然通通指向右边。

接下来我们也只需要保证我们所连的边也朝右,那么必然不可能存在环。

代码

#include<bits/stdc++.h>
#define HohleFeuerwerke using namespace std
#pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
#pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
#define int long long
HohleFeuerwerke;
inline int read(){
	int s=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
	return s*f;
}
inline void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>=10) write(x/10);
	putchar('0'+x%10);
}
const int MAXN=1e6+5;
int T,n,m,cntEdge,head[MAXN],ind[MAXN];
struct edge{
	int type;
	int from,to,next;
}e[MAXN];
vector<int> topo;
int refl[MAXN];
inline void add(int t,int u,int v){
	cntEdge++; e[cntEdge].type=t;
	e[cntEdge].from=u,e[cntEdge].to=v;
	e[cntEdge].next=head[u],head[u]=cntEdge;
}
deque<int> q;
inline bool bfs(){
	for(int i=1;i<=n;i++){
		if(ind[i]==0) q.push_back(i);
	}
	while(!q.empty()){
		int u=q.front(); q.pop_front();
		topo.push_back(u);
		for(int i=head[u];i;i=e[i].next){
			if(e[i].type==1){
				int v=e[i].to;
				if(--ind[v]==0) q.push_back(v);
			}
		}
	}
	if(topo.size()==n) return true;
	return false;
}
signed main()
{
	T=read();
	while(T--){
		n=read(),m=read(),cntEdge=0;
		topo.clear(); q.clear();
		for(int i=1;i<=n+5;i++) ind[i]=head[i]=refl[i]=0;
		for(int i=1;i<=m;i++){
			int type=read();
			int u=read(),v=read();
			if(type==1) add(1,u,v),ind[v]++;
			else add(0,u,v);
		}
		if(bfs()){
			puts("YES");
			for(int i=1;i<=n;i++) refl[topo[i-1]]=i;
			for(int i=1;i<=m;i++){
				if(e[i].type==0){
					if(refl[e[i].to]<refl[e[i].from])	
						write(e[i].to),putchar(' '),write(e[i].from),puts("");
					else write(e[i].from),putchar(' '),write(e[i].to),puts("");
				}
				else write(e[i].from),putchar(' '),write(e[i].to),puts("");
			}
		}
		else puts("NO");
	}
}
posted @ 2021-11-07 20:59  _HofFen  阅读(85)  评论(0编辑  收藏  举报