0
点赞
收藏
分享

微信扫一扫

找最大环、最小环、第一次出现的环

以前干嘛去了 2022-04-05 阅读 53
算法

Link-Cut Tree

传送门
本题是找第一次出现的环;

题面

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

二进制有一个常见的性质 2 1 + 2 2 + . . . + 2 i < 2 i + 1 2^1+2^2+...+2^i <2^{i+1} 21+22+...+2i<2i+1

那么本题其实也就是要我们求第一次出现的环;

那么考虑用并查集来处理(类似Kruskal),然后dfs一次;

Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;
struct Node{
    int v,w;
};
vector<Node> G[N];
int f[N],n,m;
int find(int x){
    if(x == f[x]) return x;
    return f[x] = find(f[x]);
}
bool merge(int u,int v){
    int fu = find(u),fv = find(v);
    if(fu == fv) return 0;
    f[fu] = fv;
    return 1;
}
vector<int> path;
bool dfs(int u,int fa,int end){
    if(u == end) return 1;
    bool ret = 0;
    for(auto to : G[u]){
        int v = to.v,w = to.w;
        if(v != fa && dfs(v,u,end)){
            path.push_back(w);
            ret = 1;
        }
    }
    return ret;
}
void solve(){
    path.clear();
    cin >> n >> m;
    for(int i=1;i<=n;++i){
        f[i] = i;
        G[i].clear();
    }
    bool flag = 0;
    for(int i=1;i<=m;++i){
        int u,v,w;
        cin >> u >> v;
        w = i;
        if(flag) continue;
        bool ff = merge(u,v);
        if(!ff){//遇到环了
            flag = 1;
            path.push_back(w);
            dfs(u,-1,v);
        }
        else{
            G[u].push_back({v,w});
            G[v].push_back({u,w});
        }
    }
    if(!flag){
        cout << -1 << '\n';
    }
    else{
        sort(path.begin(),path.end());
        int sz = path.size();
        for(int i=0;i<sz-1;++i) cout << path[i] << ' ';
        cout << path.back() << '\n';
    }
}

signed main(){
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin >> t;
    while(t--)
        solve();
    return 0;
}
举报

相关推荐

0 条评论