ICPC 澳门赛站
题意:给你\(n\)个点,\(m\)条边,第\(i\)条边的长度是\(2^i\),问你在所给的所有边中能形成的权值最小的环的边的下标,如果不能形成环则输出\(-1\)。
思路:先读入所有的边,然后贪心选择前面的边,利用并查集看当前的连个点是否在一个连通块里面,如果在就\(dfs\)回去找环,如果不在就合并集合。类似于\(Kruskal\)的思想。如何找边的下标,读入的时候记录以下边的下标,然后回溯的时候之前来的那条边不能回溯,其余就深搜回去,一直找到那个最终目标即可。
#include <bits/stdc++.h>
#define PII pair<int,int>
#define LL long long
#define fi first
#define debug(x) cout << #x << " = " << x << endl;
#define se second
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define sz(x) (int)x.size()
#define INF 2e9
#define mod 998244353
using namespace std;
const int N = 100010;
int n, m;
int x[N], y[N];
int p[N];
vector<PII>v[N];
vector<int>ans;
int find(int x){
if(p[x] != x) p[x] = find(p[x]);c
return p[x];
}
bool st[N], ok;
int cnt = 0;
void dfs(int u, int cur, int vv){
cnt ++;
if(u == vv){
int k = sz(ans);
sort(all(ans));
for(int i = 0; i < k; i ++ ){
if(i < k - 1) printf("%d ",ans[i]);
else printf("%d",ans[i]);
}
cout << "cnt = " << cnt << endl;
}
st[u] = true;
for(auto [x, y] : v[u]) {
if(x != cur){
ans.pb(y);
dfs(x, u, vv);
ans.pop_back();
cnt ++;
}
}
}
void solve()
{
scanf("%d %d",&n, &m);
ans.clear();
ok = false;
for(int i = 1; i <= m; i ++ ){
scanf("%d %d",&x[i], &y[i]);
}
for(int i = 1; i <= n; i ++ ){
p[i] = i;
v[i].clear();
}
bool ok = false;
int index;
for(int i = 1; i <= m; i ++ ){
int xx = find(x[i]), yy = find(y[i]);
if(xx == yy){
ans.pb(i);
dfs(x[i], 0, y[i]);
return;
}
p[xx] = yy;
v[x[i]].pb(make_pair(y[i], i));
v[y[i]].pb(make_pair(x[i], i));
}
printf("-1");
}
int main()
{
int test = 1;
scanf("%d",&test);
while(test -- )
{
solve();
if(test) puts("");
}
return 0;
}