题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5438
题意:有n个池塘和m个管道;每个池塘的价值是v, 现在由于资金问题要删除池塘;但是删除的池塘必须是最多只连接一个管道,否则会爆炸;
求最后相连的池塘有奇数个的价值总和是多少;
#include<iostream> #include<stdio.h> #include<string.h> #include<vector> #include<queue> using namespace std; #define N 100100 #define INF 0xfffffff int v[N], f[N], du[N], vis[N], a[N], b[N], sum[N]; vector<vector<int> > G; int Find(int x) { if(x!=f[x]) f[x] = Find(f[x]); return f[x]; } int main() { int T, n, m; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) { scanf("%d", &v[i]); f[i] = i; sum[i] = du[i] = vis[i] = 0; } G.resize(n+1); G.clear(); for(int i=1; i<=m; i++) { scanf("%d%d", &a[i], &b[i]); du[a[i]]++; du[b[i]]++; G[a[i]].push_back(b[i]); G[b[i]].push_back(a[i]); } queue<int>Q; for(int i=1; i<=n; i++) { if(du[i]<2)///把度为<2的入队,并删除; { vis[i] = 1; Q.push(i); } } while(!Q.empty()) { int p=Q.front(); Q.pop(); int len = G[p].size(); for(int j=0; j<len; j++) { int q = G[p][j]; du[q]--; if(vis[q]==0 && du[q]<2) { Q.push(q); vis[q] = 1; } } } for(int i=1; i<=m; i++)///让有联系的放到一个集合里 { if(!vis[a[i]] && !vis[b[i]]) { int pa = Find(a[i]); int pb = Find(b[i]); if(pa != pb) f[pb] = pa; } } for(int i=1; i<=n; i++) { if(!vis[i]) sum[Find(i)]++;///记录每个连通图的个数; } long long ans = 0; for(int i=1; i<=n; i++) { if(!vis[i] && sum[f[i]]%2==1)///判断是否有奇数个; ans+=v[i]; } printf("%I64d\n", ans); } return 0; }
时间: 2024-10-21 22:22:31