题意:给定一个图,然后让你把边数为1的结点删除,然后求连通块结点数为奇的权值和。
析:这个题要注意,如果删除一些结点后,又形成了新的边数为1的结点,也应该要删除,这是坑,其他的,先用并查集判一下环,然后再找连通环。
代码如下:
#include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> using namespace std ; typedef long long LL; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const double inf = 0x3f3f3f3f3f3f3f; const double eps = 1e-8; const int maxn = 1e4 + 5; const int dr[] = {0, 0, -1, 1}; const int dc[] = {-1, 1, 0, 0}; int n, m; inline bool is_in(int r, int c){ return r >= 0 && r < n && c >= 0 && c < m; } int p[maxn]; int a[maxn]; int Find(int x){ return x == p[x] ? x : p[x] = Find(p[x]); } int vis[maxn]; vector<int> vv; vector<int> G[maxn]; bool dfs(int u, int fa){ if(vis[u]) return true; if(!G[u].size()) return false; bool ok = false; vis[u] = 1; for(int i = 0; i < G[u].size(); ++i){ int v = G[u][i]; if(v == fa) continue; if(dfs(v, u)) ok = true; } if(ok) vv.push_back(u); return ok; } int main(){ int T; cin >> T; while(T--){ scanf("%d %d", &n, &m); for(int i = 0; i <= n; ++i) p[i] = i; for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]); G[i].clear(); } memset(vis, 0, sizeof(vis)); vector<int> v; // memset(in, 0, sizeof(in)); int u, w; for(int i = 0; i < m; ++i){ scanf("%d %d", &u, &w); int x = Find(u); int y = Find(w); G[u].push_back(w); G[w].push_back(u); // ++in[u]; // ++in[w]; if(x != y) p[y] = x; else v.push_back(u); } LL ans = 0; sort(v.begin(), v.end()); for(int i = 0; i < v.size(); ++i){ if(i && v[i] == v[i-1]) continue; vv.clear(); dfs(v[i], -1); if(vv.size() & 1){ for(int j = 0; j < vv.size(); ++j) ans += a[vv[j]], a[vv[j]] = 0; } } cout << ans << endl; } return 0; } /* 1 4 4 1 2 3 4 1 2 1 3 2 3 1 4 */
时间: 2024-10-16 07:42:40