Codeforces Round #656 (Div. 3) E. Directing Edges(拓扑排序)

题目传送门
首先发现初始图五有向环的话那么肯定是“YES”,否则是“NO”。然后找到一种满足要求地建树规则即可。这里采用拓扑排序建树,先dfs找出目前点的拓扑序编号,要求从编号小的连向编号大的,然后根据编号大小给无向边确定方向。这样一定满足要求,因为如果一开始没有有向环,那么沿着有向边走点的拓扑序编号一定不断变大,所以不可能产生环。

#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 50;

int T, n, m, cnt;
int num[N];
bool used[N];
vector<vector<int> > d;
vector<int> Topu;

void dfs(int u){
    used[u] = 1;
    for(auto &x : d[u])  if(!used[x])  dfs(x);
    Topu.emplace_back(u);
}

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        cnt = 0;
        bool ok = 1;
        Topu.clear();
        vector<pair<int, int> > e;
        d = vector<vector<int> >(n + 1);
        for(int i = 1; i <= n; ++i)  used[i] = 0;
        for(int i = 1, t, x, y; i <= m; ++i){
            scanf("%d%d%d", &t, &x, &y);
            if(t == 1)  d[x].emplace_back(y);
            e.emplace_back(make_pair(x, y));
        }
        for(int i = 1; i <= n; ++i) if(!used[i]) dfs(i);
		for(int i = n - 1; ~i; --i)  num[Topu[i]] = ++cnt;
        for(int i = 1; i <= n; ++i){
            for(auto &x : d[i])  if(num[i] > num[x])  ok = 0;
        }
        if(!ok)  puts("NO");
        else{
            puts("YES");
            for(auto &tt : e){
                int x = tt.first, y = tt.second;
                if(num[x] > num[y])  printf("%d %d\n", y, x);
                else  printf("%d %d\n", x, y);
            }
        }
    }
    return 0;
}
posted @ 2020-12-30 14:42  のNice  阅读(61)  评论(0编辑  收藏  举报