题解:CF1927F(Microcycle)
一、 理解题意
1. 题目链接
(1) CF链接
CodeForces-Contest-1927F
(2) LG链接
洛谷-Problem-CF1927F
2. 题目翻译
(1) 题目描述
给定一个 n n n 个点、 m m m 条边的简单无向图(每条边表示为 u u u、 v v v、 w w w,表示 u u u 和 v v v 之间有一条权值为 w w w 的边),边带权,不一定连通,保证存在至少一个简单环(没有重点、重边的环)。定义一个简单环的权值为环上边权最小的边的边权,求出该图中权值最小的简单环。
(2)输入输出
①输入格式
t t t 组数据,每组数据先输入 n n n、 m m m,随后输入 m m m 条边,每条边分别输入 u u u、 v v v、 w w w。
②输出格式
对于每组数据,输出:
第一行:找出的环的权值,空格隔开,找出的环的定点数;
第二行:按顺序输出环上的每个点的编号。
(3) 数据范围
1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104;
3 ≤ n ≤ m ≤ min ( n ⋅ ( n − 1 ) 2 , 2 ⋅ 1 0 5 ) 3 \le n \le m \le \min(\frac{n\cdot(n - 1)}{2}, 2 \cdot 10^5) 3≤n≤m≤min(2n⋅(n−1),2⋅105);
1 ≤ u , v ≤ n 1 \le u, v \le n 1≤u,v≤n, u ≠ v u \ne v u=v, 1 ≤ w ≤ 1 0 6 1 \le w \le 10^6 1≤w≤106;
m m m 总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105。
二、 分析思路
先考虑求出最小权值。
类似克鲁斯卡尔的最小生成树,我们把每条边从大到小排序,顺序遍历每条边,对于每条边,我们做如下操作:
判断端点是否已经在一个集合内,如果在,就说明通过这条边已经能够构成一个环,记录答案编号为现在编号。
随后把两个端点所在集合合并。
这里用并查集。
随后根据找到的边,从一个端点跑 d f s dfs dfs 直到跑到另一个端点(当然不能走这条边本身),维护一下路径即可。
具体看代码。
三、推测时间
O ( n + m ) O(n+m) O(n+m)。
并查集的代价忽略不计。
四、实现代码
#include<bits/stdc++.h>
#define M 220000
#define N 220000
using namespace std;
int m=0,n=0,t=0,u=0,v=0,w=0;
struct Edge{int u,v,w;bool operator<(Edge ot){return w>ot.w;}
};
Edge e[M]={};
vector<pair<int,int>>edge[N]={};
int fa[N]={},st[N]={},top=0;
bool hg[N]={};
int get_fa(int num);
bool dfs(int mb,int node,int s);
bool judge(int x,int y);
void merge(int x,int y);
int main(){scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){edge[i].clear();fa[i]=i;hg[i]=false;}for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);edge[u].push_back({v,w});edge[v].push_back({u,w});e[i]={u,v,w};}sort(e+1,e+1+m);int ans=-1;for(int i=1;i<=m;i++){int u=e[i].u,v=e[i].v;if(judge(u,v)==false){merge(u,v);}else{ans=i;}}printf("%d ",e[ans].w);hg[e[ans].v]=true;top=1;st[top]=e[ans].v;dfs(e[ans].u,e[ans].v,1);}return 0;
}
int get_fa(int num){if(fa[num]==num){return num;}fa[num]=get_fa(fa[num]);return fa[num];
}
bool dfs(int mb,int node,int s){if(node==mb){printf("%d\n",s);for(int i=1;i<=s;i++){printf("%d ",st[i]);}printf("\n");return true;}for(pair<int,int>i:edge[node]){if(hg[i.first]==false){if(i.first==mb&&s==1){continue;}hg[i.first]=true;top++;st[top]=i.first;if(dfs(mb,i.first,s+1)==true){return true;}top--;}}return false;
}
bool judge(int x,int y){int fx=get_fa(x),fy=get_fa(y);if(fx==fy){return true;}return false;
}
void merge(int x,int y){int fx=get_fa(x),fy=get_fa(y);fa[fx]=fy;return;
}