有向无环图DAG学习笔记

· · 算法·理论

前言

重学DAG。 终于没有补档了……

Update

2024-10-16: 开坑。

正文

定义

顾名思义,有向无环图(Directed Acyclic Graph,DAG)就是边有方向,没有环的图。

拓扑排序(Topological sorting,Toposort),用于给DAG的所有结点进行排序,使得所有有向边 (u,v),都有 uv 的前面。

性质

G 为DAG与图 G 可拓扑排序互为充要条件。

拓扑排序算法

BFS(Kahn)

集合 S 存放所有入度为 0 的节点,列表 L 存放拓扑序,集合 S 可以用队列或者栈维护,使用邻接表存图。

每次从 S 中取出一个点加入 L,并删除所有与其相连的边,若删除后有新的入度为 0 的点,则加入 S,直到 S 为空,算法结束。

时间复杂度为 O(n+m)

Code

#include<bits/stdc++.h>
using namespace std;
int n;
int deg[110];
vector<int> h[105];
queue<int> q;
void topo()
{
    for(int i=1;i<=n;i++)
    {
        if(deg[i]==0)
        {
            cout<<i<<" ";
            q.push(i);
        }
    }
    while(q.size())
    {
        int u=q.front();
        q.pop();
        for(int i=0;i<h[u].size();i++)
        {
            deg[h[u][i]]--;
            if(deg[h[u][i]]==0)
            {
                cout<<h[u][i]<<" ";
                q.push(h[u][i]);
            }
        }
    }
}
int main()
{   
    cin>>n;
    for(int u=1;u<=n;u++)
    {
        int v;
        while(1)
        {
            cin>>v;
            if(v==0)
                break;
            h[u].push_back(v);
            deg[v]++;
        }
    }
    topo();
    return 0;
}

DFS

dfs不需要记录入度,因为其本身就是一个拓扑排序的过程,只需在每次回溯的时候记录节点,返回的序列就是反拓扑序,将其倒过来即可,时间复杂度为 O(n+m)

Code

#include<bits/stdc++.h>
using namespace std;
int n;
bool vis[105];
vector<int> G[105];
stack<int> st;
void dfs(int u)
{
    for(auto v:G[u])
    {
        if(vis[v])
            continue;
        dfs(v);
    }
    vis[u]=1;
    st.push(u);
}
int main()
{
    cin>>n;
    for(int u=1;u<=n;u++)
    {
        int v;
        while(1)
        {
            cin>>v;
            if(v==0)
                break;
            G[u].push_back(v);
        }
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])
            dfs(i);
    while(!st.empty())
    {
        cout<<st.top()<<" ";
        st.pop();
    }
    return 0;
} 

DAG最短(长)路

一般图的最短(长)路最优时间复杂度为Bellman_ford的 O(nm) 和Dijkstra的 O(m \log n),但是如果是DAG,使用拓扑排序可以优化到 O(n+m)

先进行拓扑排序,得出拓扑序 L 后对每个元素进行松弛操作即可。

算法过水,代码就不给了。

结尾

感谢设计算法与实现代码的大神们。

本文算法资料来自OI-WIKI,在此特意声明,以示感谢。