链接:https://codeforces.com/contest/1927/problem/F
思路:题意是找一个拥有最小边权的环,首先是确定怎么找环,可以用并查集维护一下,如果两点不在一个集合里则将两点合并,如果新找的边的两个点本身就在一个集合,那么这条边可以构成一个环。我们将边权从大到小排序后通过上面所说的遍历所有的边,每次找到新的第二种情况,就把此边当环的最小边权。结束后最终的得到的就是环的最小边权,两点为u,v。然后我们将除这条边的其他边去建图,然后用pre数组去维护路径,最终找到一条新的从u到v的路径就是答案。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define x first
#define y second
#define pb push_back
using namespace std;
typedef pair<int, int>PII;
int n, m, ed;
map<int, int>mp;
struct edge{
int x,y,w;
}a[200005];
int p[200005];
vector<int>g[200006],vis(200005),pre(200050);
int find(int x){
return x==p[x]?p[x]:(p[x]=find(p[x]));
}
bool merge(int x,int y){//判断两点是否已经是一个集合了
int u=find(x);
int v=find(y);
if(u==v)return true;//如果是,则这条边可以和这个集合的某些点构成环
p[u]=v;//将两点合并到同一集合
return false;//这条边目前无法构成环
}
void dfs(int x){
for(auto v:g[x]){
if(vis[v])continue;
pre[v]=x;vis[x]=1;
dfs(v);
}
}
void solve () {
cin>>n>>m;
for(int i=1;i<=n;i++)p[i]=i,g[i].clear(),vis[i]=0,pre[i]=-1;//初始化
for(int i=1;i<=m;i++){
int x,y,z;
cin>>x>>y>>z;
a[i]={x,y,z};
}
sort(a+1,a+m+1,[](edge x,edge y){//从大到小排序,每次找到的可以构成环的边权逐渐变小
return x.w>y.w;
});
int mi=1e18,id=-1;
for(int i=1;i<=m;i++){
if(merge(a[i].x,a[i].y)){//如果是,则这条边可以和这个集合的某些点构成环
mi=a[i].w;
id=i;
}
}
for(int i=1;i<=m;i++){
if(id!=i){
g[a[i].x].pb(a[i].y);
g[a[i].y].pb(a[i].x);
}
}
cout<<mi<<" ";vis[a[id].x]=1;
// cerr<<a[id].x<<" "<<a[id].y<<endl;
dfs(a[id].x);
vector<int>ans;
for(int i=a[id].y;i!=-1;i=pre[i]){
ans.pb(i);
}
cout<<ans.size()<<endl;
for(auto v:ans)cout<<v<<" ";
cout<<endl;
}
signed main () {
int T = 1;
std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>T;
while (T --) solve ();
return 0;
}