图论找环

百般思念 提交于 2019-12-02 10:55:01

竞赛中找环有许多种问题,判断是否有环,找到环上的点,找到环上的边等等。

而只需要找到环上相邻的两点,或者环上的一条边就可以解决这三个问题。

有向图中,可以用拓扑排序的方法,把将拓扑排序完后限制条件仍未被清零的点即在环上的点。

#include <bits/stdc++.h>
#define N 1000101
using namespace std;
int n, m, cnt, lin[N], deg[N];
struct edg {
    int to, nex;
}e[N];
inline void add(int f, int t)
{
    deg[t]++;
    e[++cnt].nex = lin[f];
    e[cnt].to = t;
    lin[f] = cnt;
}
void topu()
{
    queue <int> q;
    for (int i = 1; i <= n; i++)    
        if (!deg[i]) q.push(i);
    while (!q.empty())
    {
        int cur = q.front(); q.pop();
        for (int i = lin[now]; i; i = e[i].nex)
        {
            int to = e[i].to;
            deg[to]--;
            if (!deg[to]) q.push(to);   
        }
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b); 
    }
    topu();  
    for (int i = 1; i <= n; i++)
        if (deg[i])
            printf("%d ", i);
    return 0;
}            

无向图中,就不能用拓扑排序了,比较好的方法就是并查集。

并查集通过判断每一条边的两个端点是否在一个一个集合内来找到在同一个环上的两个边,然后以这两个点为起点和终点搜索,最终输出所有在他们路径上的点。

#include <bits/stdc++.h>
#define N 1001011
using namespace std;
int n, m, cnt, fa[N], lin[N], vis[N], ha[N];
int find(int a)
{   
    if (fa[a] == a)
    return a;
    return fa[a] = find(fa[a]);
}   
struct edg {
    int to, nex, from;
}e[1001001];
inline void add(int f, int t )
{
    e[++cnt].to = t;
    e[cnt].from = f;
    e[cnt].nex = lin[f];
    lin[f] = cnt;
}
int dfs(int now, int end)
{
    if (now == end) return 1;
    int flag = 0;
    for (int i = lin[now]; i; i = e[i].nex)
    {
        int to = e[i].to;
        if (vis[to]) continue;
        vis[to] = 1;
        flag = max(flag, dfs(to, end));
        if (flag) ha[now] = ha[to] = 1;
        vis[to] = 0;    
    }
    return flag;
}
int main()
{
    scanf("%d%d", &n, &m); 
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    for (int i = 1, a, b; i <= n; i++)
    {
        scanf("%d%d", &a, &b);
        add(a, b);
        add(b, a);
        int faa = find(a), fab = find(b);
        memset(vis, 0, sizeof(vis));
        if (faa == fab) //说明他们已经在同一个集合里 
            dfs(a, b);
        fa[faa] = fab;
    }
    for (int i = 1; i <= n; i++)
        if (ha[i]) 
            printf("%d ", i);
    return 0;
} 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!