三十年河东,三十年河西|

自动机

园龄:1年10个月粉丝:2关注:4

图找环

如标题所示,本文主要探讨无向图/有向图中环的做法

1. 拓扑排序判断环是否存在

在一个途中,如果点i和点j之间存在一条路径,则认为这两个点相互依赖, 而在拓扑序中每个点只会和后面的点产生依赖关系,由此可知如果图中存在环那么一定不存在拓扑序
那么应该如何求拓扑序呢?

bool toposort() {
  vector<int> L;
  queue<int> S;
  for (int i = 1; i <= n; i++)
    if (in[i] == 0) S.push(i); // in[]存的入度,如果是无向图则让度<=1 的入队 
  while (!S.empty()) {
    int u = S.front();
    S.pop();
    L.push_back(u);
    for (auto v : G[u]) {
      if (--in[v] == 0) {
        S.push(v);
      }
    }
  }
  if (L.size() == n) {
    for (auto i : L) cout << i << ' ';
    return true;
  } else {
    return false;
  }
}

2. 并查集判断环的个数

我们每向图中添加一条边(u, v)时,如果uv 已经在集合当中则说明u, v可以借助集合中某点x形成依赖关系,然而(u, v)本身就有依赖关系,那么(u, v, x)形成一个环

inline void solve() 
{
    int n, m; cin >> n >> m;
    DSU dsu(n + 1);
    int ans = 0;
    for (int i = 0; i < m; i++)
    {
        int a, b; cin >> a >> b;
        if (!dsu.merge(a, b)) ans++; // 如果是有向图则判断find(u) == v, 不成环就merge(v, u)
    }

    cout << ans << endl;
}

3. 暴力循环判断环的长度(只有一个出度的情况)

例题,因为按照题意图中一定有环,所以就没事先判断环是否存在
存在环的话,可以从一个点一直往前走,如果有一个点被走了两次那么它一定在环里面

inline void solve() 
{
    int n, k; cin >> n >> k;
    std::vector<int> adj(n + 1);
 
    int flag = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> adj[i];
        if (i == adj[i]) flag++;
    }
 
    if (k == 1)
    {
        string s =  flag == n ? "Yes" : "No";
        cout << s << endl;
        return;
    }
    
    vector<int> cnt(n + 1, 0);
    vector<bool> st(n + 1);
    for (int i = 1; i <= n; i++)
    {
        if (cnt[i] != 0) continue;
        int a = i;
        while (!cnt[a])
        {
            cnt[a] = 1;
            a = adj[a];
        }
 
        if (cnt[a] == 1 && !st[a]) // 这个环已经没走过,cnt[a] = 2 说明之前走过
        {
            int t = 1;
            int nx = adj[a];
            while (a != nx)
            {
                t++;
                nx = adj[nx];
            }
 
            if (t != k)
            {
                cout << "No" << endl;
                return;
            }
        }
 
        for (int j = i; !st[j]; j = adj[j]) // 将已经走过的路经打标记
        {
            st[j] = true;
        }
    }
    
    cout << "Yes" << endl;
}

本文作者:自动机

本文链接:https://www.cnblogs.com/monituihuo/p/17628789.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   自动机  阅读(50)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起