【图论】拓扑排序

算法一:

寻找入度为0(没有任何结点指向它)的结点Q,删除Q及与Q相连的边。

重复上述操作直到结点被全部删除,或找不到入度为0的结点(存在有向环,非DAG)。


算法二:

遍历每一个结点,通过DFS访问结点的所有子孙。当前结点无子孙时为递归边界,将结点加入到当前拓扑序的首部

需要注意的是,要判断递归路上是否有遇到存在有向环的结点,故要用\(vis[u]\)存储结点状态:

\(vis[u]=0\)时,结点\(u\)从未访问过;

\(vis[u]=-1\)时,结点\(u\)正在访问;

\(vis[u]=1\)时,结点\(u\)已访问完毕。

int E[1000 + 10][1000 + 10];
int vis[100 + 10];
int topo[100 + 10];
int n, m, pos;
bool dfs(int V) {
    vis[V] = -1;
    for (int u = 1;u <= n;u++) {
        if (E[V][u]) {
            if (vis[u] < 0) return false;//存在有向环
            else if (!vis[u] && !dfs(u)) return false;//没访问过的新结点进行访问,但过程中出现有向环
        }
    }
    vis[V] = 1;
    topo[pos] = V;
    pos--;
    return true;
}

bool toposort() {
    for (int u = 1;u <= n;u++) {
        if (!vis[u] && !dfs(u))return false;
    }
    return true;
}

int main()
{
    while (cin >> n >> m) {
        if (!n && !m) break;
        memset(E, 0, sizeof(E));
        memset(topo, 0, sizeof(topo));
        memset(vis, 0, sizeof(vis));
        pos = n;
        for (int i = 1;i <= m;i++) {
            int a, b;
            cin >> a >> b;
            E[a][b] = 1;
        }
        if (toposort()) {
            cout << topo[1];
            for (int i = 2;i <= n;i++) cout << " " << topo[i];
            cout << endl;
        }
    }
    return 0;
}
posted @ 2020-04-09 02:46  StreamAzure  阅读(179)  评论(0编辑  收藏  举报