HDU 5438 Ponds 拓扑序+并查集/DFS

来源:互联网 发布:全栈工程师的定义知乎 编辑:程序博客网 时间:2024/04/28 11:58

就是给一个图,每个点有权值,边没有。然后会先依次删除度数<=1的点,一直删到不能删为止。然后求所有连通块中节点数为奇数的连通块的权值和的和。

首先删点就是拓扑序来删,然后求连通块可以DFS或者BFS或者并查集都可以。

训练时刚结束后,队友改了改,过的,直接邻接表(当然是vector存),拓扑序+BFS求连通块过掉的。

嗯,然后,去网上学了一发链式前向星,然后并查集搞连通块的,但我不清楚那些人用了链式前向星了,还要用两个数组来保存所有的边在并查集的时候用,链式前向星就可以遍历所有边啊,复杂度也是一样的。反正窝把存边的两个数组删掉后也A了。嗯,不管他们了。

代码:

#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define maxn 10003#define maxm 100003struct Edge{int next, to, w;Edge() :next(0), to(0), w(0) { }}edge[maxm];int head[maxn], cnt = 0;int val[maxn], degree[maxn];bool vis[maxn];//记录该点是否被访问int n, m;int set[maxn];int size[maxn];//结点数long long sum[maxn];void init_set(){for (int i = 1; i<maxn; ++i){set[i] = i;size[i] = 1;sum[i] = val[i];}}int findSet(int x)//路径压缩{if (x == set[x])return x;elsereturn set[x] = findSet(set[x]);}void unionSet(int x, int y)//启发式合并{int fx = findSet(x);int fy = findSet(y);if (fy == fx)return;if (size[fx] >= size[fy]){size[fx] += size[fy];set[fy] = fx;sum[fx] += sum[fy];}else{size[fy] += size[fx];set[fx] = fy;sum[fy] += sum[fx];}}void add(int u, int v, int w = 1){edge[cnt].w = w;edge[cnt].to = v;edge[cnt].next = head[u];head[u] = cnt++;}void topo_del(){queue<int> que;for (int i = 1; i <= n; ++i){if (degree[i] <= 1){degree[i] = 0;vis[i] = false;que.push(i);}}while (!que.empty()){int x = que.front();que.pop();for (int i = head[x]; i != 0; i = edge[i].next){int y = edge[i].to;if (vis[y]){degree[y]--;if (degree[y] == 1){vis[y] = false;que.push(y);}}}}}int main(){//freopen("input.txt", "r", stdin);int T;scanf("%d", &T);while (T--){long long ans = 0;scanf("%d%d", &n, &m);Edge etmp;cnt = 1;memset(vis, true, sizeof(bool)*maxn);memset(degree, 0, sizeof(int)*maxn);memset(head, 0, sizeof(int)*maxn);memset(val, 0, sizeof(int)*maxn);for (int i = 0; i < maxm; ++i)edge[i] = etmp;for (int i = 1; i <= n; ++i)scanf("%d", &val[i]);int a, b;for (int i = 0; i < m; ++i){scanf("%d%d", &a, &b);add(a, b);add(b, a);degree[a]++;degree[b]++;}topo_del();init_set();for (int i = 1; i <= n; ++i){for (int j = head[i]; j != 0; j = edge[j].next)if (vis[i] && vis[edge[j].to])unionSet(i, edge[j].to);}for (int i = 1; i <= n; ++i)if (vis[i] && set[i] == i&&size[i] & 1)ans += sum[i];printf("%I64d\n", ans);}//while (1);//system("pause");return 0;}

0 0