图论-并查集

1.
模板题:多余的边
思路:n条边n个点。类似于克鲁斯卡尔,加边的同时用并查集判断边的两端点是否同根,若同根,则要删除该边。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2000;
int main()
{
    int n;
    cin>>n;
    vector<int>fa(n+1);
    for(int i=1;i<=n;i++)fa[i]=i;
    auto find=[&](auto &&find,int x)->int{
        if(fa[x]==x)return x;
        return fa[x]=find(find,fa[x]);
    };
    auto join=[&](int x,int y)->int{
        int xx=find(find,x);
        int yy=find(find,y);
        if(xx==yy)return 1;
        fa[xx]=yy;
        return 0;
    };
    int a,b;
    for(int i=0;i<n;i++){
        int s,t;
        cin>>s>>t;
        if(join(s,t)){
            a=s;
            b=t;
        }
    }
    cout<<a<<' '<<b<<'\n';
}

2.
多余的边(二)
思路:n条边n个点。与模板题不同的是该图是有向图。
分为三种情况(见力扣评论区):
(1)每个点入度是1,有一个有向环。解决:同模板题,随便删除环上一边。
(2)存在一个入度为2的点,无有向环。解决:随便删除指向该点的两条边中的其中一条。
(3)既存在有向环,又存在一个入度为2的点(肯定在环上)。解决:肯定要删除环上指向入度为2点的那条边,用并查集。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2000;
vector<int>v[N];
int main()
{
    int n;
    cin>>n;
    vector<int>fa(n+1);
    vector<int>in(n+1);
    for(int i=1;i<=n;i++)fa[i]=i;
    auto find=[&](auto &&find,int x)->int{
        if(fa[x]==x)return x;
        return fa[x]=find(find,fa[x]);
    };
    auto join=[&](int x,int y)->int{
        int xx=find(find,x);
        int yy=find(find,y);
        if(xx==yy)return 1;
        fa[xx]=yy;
        return 0;
    };
    int a,b;
    int f=0;
    for(int i=0;i<n;i++){
        int s,t;
        cin>>s>>t;
        if(f)continue;//搞定入度为2的点就成功了
        v[t].push_back(s);//反着存,方便找指向入度为2点的边
        in[t]++;
        if(in[t]>1){
            f=1;
            if(join(s,t))a=s,b=t;
            else a=v[t][0],b=t;
            continue;
        }
        if(join(s,t)){
            a=s;
            b=t;
        }
    }
    cout<<a<<' '<<b<<'\n';
}
posted @ 2026-01-23 21:17  spark_of_fire  阅读(9)  评论(0)    收藏  举报