1. 程式人生 > 實用技巧 >Codeforces Round #656 (Div. 3) E - Directing Edges

Codeforces Round #656 (Div. 3) E - Directing Edges

連結

https://codeforces.com/contest/1385/problem/E

題意

給定一張圖,既有 有向邊,也有 無向邊,要求給每個無向邊加上方向使得最終整張圖無環。
若存在方案輸出Yes,並輸出每條無向邊的方向,否則輸出No

思路

先說結論,拋開無向邊,如果有向邊構成的圖本身成環,那麼明顯是No,否則一定是Yes
如何判斷是否成環呢,我們可以利用拓撲序,假設存在一條有向邊A->B,如果圖中有環,那麼B的拓撲序應該小於A,也即存在一條B到A的路徑
有了拓撲序我們就可以利用它來輸出Yes時的方案了
對於每條無向邊AB,假設A的拓撲序小於B,那麼該邊的方向就應該為A->B,否則就會如上所說成環

程式碼

#include <bits/stdc++.h>

using namespace std;

vector<int> ord;
vector<int> used;
vector<vector<int>> g;

void dfs(int v) {
	used[v] = 1;
	for (auto to : g[v]) {
		if (!used[to]) dfs(to);
	}
	ord.push_back(v);
}

int main() {
#ifdef _DEBUG
	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);
#endif
	
	int t;
	cin >> t;
	while (t--) {
		int n, m;
		cin >> n >> m;
		g = vector<vector<int>>(n);
		vector<pair<int, int>> edges;
		for (int i = 0; i < m; ++i) {
			int t, x, y;
			cin >> t >> x >> y;
			--x, --y;
			if (t == 1) {
				g[x].push_back(y);
			}
			edges.push_back({x, y});
		}
		
		ord.clear();
		used = vector<int>(n);
		for (int i = 0; i < n; ++i) {
			if (!used[i]) dfs(i);
		}
		vector<int> pos(n);
		reverse(ord.begin(), ord.end());
		for (int i = 0; i < n; ++i) {
			pos[ord[i]] = i;
		}
		bool bad = false;
		for (int i = 0; i < n; ++i) {
			for (auto j : g[i]) {
				if (pos[i] > pos[j]) bad = true;
			}
		}
		if (bad) {
			cout << "NO" << endl;
		} else {
			cout << "YES" << endl;
			for (auto [x, y] : edges) {
				if (pos[x] < pos[y]) {
					cout << x + 1 << " " << y + 1 << endl;
				} else {
					cout << y + 1 << " " << x + 1 << endl;
				}
			}
		}
	}
	
	return 0;
}

vector太好用了,就直接把題解的程式碼貼上來了(