题解:CF1927F(Microcycle)
一、 理解题意
1. 题目链接
(1) CF链接
(2) LG链接
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;
}