代码随想录-训练营-day47

108. 冗余连接 (kamacoder.com)

题目描述有点长,就不放这了,简单来说就是如何找到无向无环图中的冗余边。

非常标准的模板题啊,因为我们要知道并查集中的isSame函数就是专门用来查图中节点的链接情况的,如果一个点出现了冗余边,产生冗余边的两个节点就是符合isSame的要求,所以我们只需要在构建图的过程中不断判断两个点是否isSame即可。

代码如下:

#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> father(1001);
void init(){
    for(int i=1;i<=n;++i){
        father[i]=i;
    }
}
int find(int u){
    return father[u]==u?u:father[u]=find(father[u]);
}
bool isSame(int u,int v){
    u=find(u);
    v=find(v);
    return u==v;
}
void join(int u,int v){
    u=find(u);
    v=find(v);
    if(u==v)return;
    else father[v]=u;
}
int main(){
    cin>>n;
    int s,t;
    init();
    for(int i=0;i<n;++i){
        cin>>s>>t;
        if(isSame(s,t)){
            cout<<s<<" "<<t<<endl;
            return 0;
        }
        else{
            join(s,t);
        }
    }
    return -1;
}

109. 冗余连接II (kamacoder.com)

这个题相比起上一个题,只是将无向图换成了有向图,但是我们要判断的东西就多了不少。

比起无向图来说,我们的冗余边的情况要复杂一些,我们可以通过每个点的入度来作为判断的标准:更具体地说,我们产生冗余边有两种情况,一种是有向环图,一种是有向的无环图。环图的话 不会出现入度为2的点,那么我们直接去删除环中的一条边即可;反之如果我们找到入度为2的点,那么我们还要考虑删除哪条边能保证删除后的图仍然是有向图。

代码如下:

#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> father(1001);
void init(){
    for(int i=0;i<n;++i){
        father[i]=i;
    }
}
int find(int u){
    return u==father[u]?u:father[u]=find(father[u]);
}
bool same(int u,int v){
    u=find(u);
    v=find(v);
    return u==v;
}
void join(int u,int v){
    u=find(u);
    v=find(v);
    if(u==v)return;
    father[v]=u;
}
bool isTreeAfterRemove(const vector<vector<int>>& edges,int deleteEdge){
    init();
    for(int i=0;i<n;++i){
        if(i==deleteEdge)continue;
        if(same(edges[i][0],edges[i][1]))return false;
        join(edges[i][0],edges[i][1]);
    }
    return true;
}
void getRemove(const vector<vector<int>>& edges){
    init();
    for(int i=0;i<n;++i){
        if(same(edges[i][0],edges[i][1])){
            cout<<edges[i][0]<<" "<<edges[i][1]<<endl;
            return;
        }
        join(edges[i][0],edges[i][1]);
    }
}
int main(){
    cin>>n;
    int s,t;
    vector<vector<int>> edges;
    vector<int> inDegrees(n+1,0);
    for(int i=0;i<n;++i){
        cin>>s>>t;
        edges.push_back({s,t});
        inDegrees[t]++;
    }
    vector<int> vec;
    for(int i=n-1;i>=0;--i){
        if(inDegrees[edges[i][1]]==2)vec.push_back(i);
    }
    if(vec.size()>0){
        if(isTreeAfterRemove(edges,vec[0]))cout<<edges[vec[0]][0]<<" "<<edges[vec[0]][1]<<endl;
        else cout<<edges[vec[1]][0]<<" "<<edges[vec[1]][1]<<endl;
        return 0;
    }
    getRemove(edges);
}