拓扑排序的性质

拓扑排序的性质:排完序之后,若最后tt存的不是n-1,即未把所有点都打入q,q[i]存的是拓扑排序后第i个点是多少,可以用s[q[i]]=i,方便取用,如果全部入q,不论是不是一个连通块,只要无环,就会全部入q,之后,按照先后顺序排点即可

给定一个由 nn 个点和 mm 条边构成的图。

不保证给定的图是连通的。

图中的一部分边的方向已经确定,你不能改变它们的方向。

剩下的边还未确定方向,你需要为每一条还未确定方向的边指定方向。

你需要保证在确定所有边的方向后,生成的图是一个有向无环图(即所有边都是有向的且没有有向环的图)。

输入格式

第一行包含整数 TT,表示共有 TT 组测试数据。

每组数据第一行包含两个整数 n,mn,m。

接下来 mm 行,每行包含三个整数 t,x,yt,x,y,用来描述一条边的信息,其中 tt 表示边的状态,如果 t=0t=0,则表示边是无向边,如果 t=1t=1,则表示边是有向边。x,yx,y 表示这条边连接的两个端点,如果是有向边则边的方向是从 xx 指向 yy。

保证图中没有重边(给定了 (x,y)(x,y),就不会再次出现 (x,y)(x,y) 或出现 (y,x)(y,x))和自环(不会出现 x=yx=y 的情况)。

输出格式

对于每组数据,如果无法构造出有向无环图,则输出一行 NO

否则,先输出一行 YES,随后 mm 行,每行包含两个整数 x,yx,y,用来描述最终构造成的有向无环图中的每条边的具体方向(xx 指向 yy),边的先后顺序随意。

注意,已经确定方向的边,不能更改方向。

如果答案不唯一,输出任意合理方案均可。

数据范围

对于前三个测试点,1n,m101≤n,m≤10。
对于全部测试点,1T200001≤T≤20000,2n2×1052≤n≤2×105,1mmin(2×105,n(n1)2)1≤m≤min(2×105,n(n−1)2),0t10≤t≤1,1x,yn1≤x,y≤n。
保证在一个测试点中,所有 nn 的和不超过 2×1052×105,所有 mm 的和不超过 2×1052×105。

输入样例:

4
3 1
0 1 3
5 5
0 2 1
1 1 5
1 5 4
0 5 2
1 3 5
4 5
1 1 2
0 4 3
1 3 1
0 2 3
1 2 4
4 5
1 4 1
1 1 3
0 1 2
1 2 4
1 3 2

输出样例:

YES
3 1
YES
2 1
1 5
5 4
2 5
3 5
YES
1 2
3 4
3 1
3 2
2 4
NO
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 2e5 + 10;

int n, m;
int h[N], e[N], ne[N], d[N], idx;
int q[N];
int S[N];

struct Edge
{
    int x, y;
}edges[N];

void add(int a, int b)  // 添加一条边a->b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
bool topsort()  //拓扑排序
{
    int hh = 0, tt = -1;

    // d[i] 存储点i的入度
    for (int i = 1; i <= n; i ++ )
        if (!d[i])
            q[ ++ tt] = i, S[i] = tt;

    while (hh <= tt)
    {
        int t = q[hh ++ ];

        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (-- d[j] == 0)
                q[ ++ tt] = j, S[j] = tt;
        }
    }
    return tt == n - 1;
}
void solve()
{
    scanf("%d%d", &n, &m);

    idx = 0;
    memset(d,  0, (n + 1) * 4);
    memset(h, -1, (n + 1) * 4);

    for (int i = 0; i < m; ++ i)
    {
        int t, a, b;
        scanf("%d%d%d", &t, &a, &b);
        if (t) add(a, b), ++ d[b];
        edges[i] = {a, b};
    }
    if (!topsort()) puts("NO");
    else
    {
        puts("YES");
        for (int i = 0; i < m; ++ i)
        {
            auto &t = edges[i];
            if (S[t.x] < S[t.y]) printf("%d %d\n", t.x, t.y);
            else printf("%d %d\n", t.y, t.x);
        }
    }
}
int main()
{
    int T = 1;
    scanf("%d", &T);
    while (T -- ) solve();
    return 0;
}

 

posted @ 2021-10-12 22:01  兮何其  阅读(121)  评论(0)    收藏  举报