侧边栏

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太好用了,就直接把题解的代码贴上来了(

posted @ 2020-07-18 21:01  晴人  阅读(148)  评论(0编辑  收藏  举报