HDU 5438
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5438
题意:
一些点一些边。每次去除只有一条边和该点相邻的点,并把该点的边全删除。
问最后点数为奇数个的连通块里面点的权值和。
思路:
Topo,然后任意姿势求奇数个点的集合。
并查集比较好实现,dfs亦可。你非要双连通缩点我也没有办法。
源码:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <ctime>
#include <climits>
#include <cassert>
#include <cmath>
#include <string>
#include <bitset>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#include <utility>
#include <numeric>
#define LL long long
#define gmax(a,b) ((a) > (b) ? (a) : (b))
#define gmin(a,b) ((a) < (b) ? (a) : (b))
#define MOD (1000000007)
using namespace std;
/*注意是边不是点*/
const int MAXN = 1e4 + 5;
vector<int>lin[MAXN];
int n, m;
long long data[MAXN];
int in[MAXN];
queue<int>que;
int use[MAXN];
long long tans;
int dfs(int u)
{
int ans = 1;
use[u] = 1;
tans += data[u];
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
if(use[v] == 0) ans += dfs(v);
}
return ans;
}
int main()
{
// freopen("1002.in", "r", stdin);
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
for(int i = 1 ; i <= n ; i++)
in[i] = 0, lin[i].clear(), scanf("%I64d", &data[i]);
int u, v;
for(int i = 1 ; i <= m ; i++){
scanf("%d%d", &u, &v);
lin[u].push_back(v);
lin[v].push_back(u);
in[u]++;
in[v]++;
}
memset(use, 0, sizeof(use));
while(!que.empty()) que.pop();
for(int i = 1 ; i <= n ; i++)
if(in[i] <= 1) que.push(i), use[i] = 1;
while(!que.empty()){
int u = que.front(); que.pop();
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
in[v]--;
if(use[v] == 0 && in[v] <= 1) que.push(v), use[v] = 1;
}
}
long long ans = 0;
for(int i = 1 ; i <= n ; i++){
if(use[i] == 0){
tans = 0;
int num = dfs(i);
if(num % 2 == 1)
ans += tans;
}
}
printf("%I64d\n", ans);
}
return 0;
}