1. 程式人生 > 其它 >第46屆ICPC澳門站 K - Link-Cut Tree // 貪心 + 並查集 + DFS

第46屆ICPC澳門站 K - Link-Cut Tree // 貪心 + 並查集 + DFS

原題連結:K-Link-Cut Tree_第46屆ICPC 東亞洲區域賽(澳門)(正式賽) (nowcoder.com)

 

題意:

要求一個邊權值總和最小的環,並從小到大輸出邊權值(2的次冪);若不存在環,輸出-1。

 

思路:

考慮按權值從小到大加邊,當出現環時(利用並查集判環),這個環必定是總權值最小的環。

找到環後,不再加邊,並從環上某一點做DFS,找到從該點出發並再次回到該點的環。

 

程式碼:

#include <bits/stdc++.h>
#define PII pair<int,int>
#define fi first
#define se second
using
namespace std; const int N = 100010; int n, m, fa[N], stk[N], top; vector<PII> v[N]; bool vis[N], mark; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void dfs(int u, int pre, int ed) { if(mark) return; if(u == ed && ~pre) { mark = true; sort(stk
+ 1, stk + 1 + top); for(int i = 1; i <= top; i++) printf("%d ", stk[i]); cout << endl; } for(auto i : v[u]) { if(vis[i.fi] || i.fi == pre) continue; stk[++top] = i.se, vis[i.fi] = true; dfs(i.fi, u, ed); -- top, vis[i.fi] = false; } }
void solve() { cin >> n >> m; for(int i = 1; i <= n; i++) { fa[i] = i, vis[i] = false; v[i].clear(); } int st = 0; bool flag = false; // 是否存在環 for(int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); if(flag) continue; v[x].push_back({y, i}), v[y].push_back({x, i}); int fx = find(x), fy = find(y); if(fx == fy) flag = true, st = x; else fa[fx] = fy; } if(!flag) puts("-1"); else mark = false, dfs(st, -1, st); } int main() { int test; cin >> test; while(test--) solve(); return 0; }