1. 程式人生 > 其它 >【拓撲排序】【CF好題】E. Directing Edges

【拓撲排序】【CF好題】E. Directing Edges

【拓撲排序】【好題】E. Directing Edges

傳送門

題意

給你一些點和邊,邊中既有有向邊和無向邊,求通過對所有無向邊賦予方向後,這張圖是否能構成一張有向無環圖(DAG)。

思路分析

由於沒有辦法更改已經形成的有向邊的方向,所以如果圖中的有向邊已經形成了環,那麼就很明確的無法構成一張DAG圖了。

而對於無向邊的圖我們可以把它們先看成是一個個孤立的點,又結合拓撲排序及拓撲序標記的性質,我們可以知道這些點是夥同有向邊中入度為0的點在第一輪的時候就加入到佇列中去。也就是它們的拓撲序肯定是小於第二輪加入的點,而我們又知道在拓撲排序中,一條有向邊的起點的拓撲序是要小於這條有向邊的拓撲序的。

且若在這張圖存在環,也就是說這張圖中存在一些點它的入度無法通過拓撲排序的消解的過程變成0,因為只需要將拓撲排序實際處理的點數和總點數進行一個比較就可以知道這張圖中是否具有環。

#include <bits/stdc++.h>
#define pii pair<int,int>
#define FI first
#define SE second
using namespace std;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N = 2E5+100,M = 2E5+100;
struct edge{
    int u,v,ne;
}edges[M];
int h[N],idx;
void add(int u,int v)
{
	edges[idx] = {u,v,h[u]};
	h[u] = idx++;
}
int n,m;
int indu[N],order[N],time_stamp = 0;
void topo()
{
	queue<int> q;
	for(int i=1;i<=n;i++)
		if(!indu[i]) q.push(i);
	

	while(q.size())
	{	
		int u =q.front();
		q.pop();
		order[u] = ++time_stamp;
		for(int i=h[u];~i;i=edges[i].ne)
		{
			int v = edges[i].v;
			indu[v]--;
			if(!indu[v])
			   q.push(v);
		}
	}
}
vector<pii> ans;
void init()
{
	ans.clear();
	for(int i=1;i<=n;i++)
	   h[i] = -1,order[i] = indu[i] = time_stamp = idx = 0;
}
int main()
{
	int T = read();
	while(T--)
	{
		n = read(),m = read();
		init();
		for(int i = 1;i <= m;i++)
		{
			int f = read(), u = read(), v = read();
			ans.push_back({u,v});
			if(f) add(u,v),indu[v]++;
		}
	
		topo();	
		if(time_stamp<n)
	       printf("NO\n");
	    else 
    	{
	    	printf("YES\n");
		    for(int i=0;i<ans.size();i++)
	        {
		        int u = ans[i].FI, v = ans[i].SE;
	    	    if(order[u]>order[v]) 
		            swap(u,v);
		        printf("%d %d\n",u,v);
	        }
        }
	}
    return 0;
}