1. 程式人生 > 其它 >ICPC 澳門賽站 K.Link-Cut Tree

ICPC 澳門賽站 K.Link-Cut Tree

ICPC 澳門賽站

K.Link-Cut Tree

題意:給你\(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;
}