HDU 3367 Pseudoforest (最小生成树,并查集)
来源:互联网 发布:eas 数据字典 编辑:程序博客网 时间:2024/06/13 01:12
题目链接
题意
题目先给出了伪森林的定义,伪森林首先是一个无向图,他的每一个连通分量最多只能包含一个环。然后一个伪森林的值是其所包含的所有的边的权值之和。题目输入一个无向图,要求输出该图所能生成的最大伪森林的值。图上有n个点,有m条边,每条边的两个端点分别为u和v,其权值为c。
数据范围的一些限定
0 < n <= 10000
0 <= m <= 100000
0 <= u,v < n
0 < c <= 10000
思路
跟最小生成树算法的思想有点儿像,先对每一条边按照权值从大到小进行排序,然后每次取出剩余的最大的边,判断两个端点是否符合插入最大伪森林的条件(条件一会儿再说),如果符合,就插入伪森林并更新伪森林的值。
要判断一条边的两个端点是否符合插入最大伪森林的条件,首先是要判断这两个端点是否属于同一个连通分量,这个很容易判断,跟最小生成树算法里的一样,用并查集实现,如果他们在并查集中具有相同的根,则他们属于同一个连通分量,否则他们不属于同一个连通分量。下一步是判断两个端点所在的连通分量是否具有环,只需要有一个变量标记其在并查集中的根即可,每个根都有,开个bool数组呗,要记得初始化。如果某条边的两个端点属于同一个连通分量,加上这条边,那么该连通分量必然会增加一个环,则在插入当前边前需要判断当前连通分量中是否有环,有环,则不能插入,无环,则插入并更新伪森林的值。如果这条边的两个端点不属于同一个连通分量,则需判断两个连通分量是否都具有环,若这两个连通分量中最多只有一个环,则可以插入这条边合并两个连通分量,更新伪森林的值,有环的时候还要更新伪森林的环标记,否则不能插入这条边。
最后数据量略大,不能用cin,cout啊。。坑爹的我用cin和cout TLE了一次,然后换成scanf和printf就AC了。。
以下是代码,各种多余头文件宏定义什么的请无视,在vimrc里写好了,懒得删掉了,可以视为我在装13。如果在其中发现有错误,请指出,发表此文部分原因是希望有人能够指出我可能存在的错误。如果有人有更好的解法,请不吝赐教。
/* * Author: Fiend * Created Time: 2013/4/14 1:27:35 * File Name: test.cpp */#include <iostream>#include <cstdio>#include <cstddef>#include <cmath>#include <algorithm>#include <string>#include <cstring>#include <vector>#include <bitset>#include <stack>#include <queue>#include <set>#include <map>#include <cctype>#define ST size_type#define PB push_back#define LL long long#define MAXN 10005#define MAXM 100005using std::cin;using std::cout;using std::endl;using std::string;using std::bitset;using std::vector;using std::pair;using std::swap;using std::sort;using std::max;using std::min;const int inf = 0x3fffffff;typedef pair<int, int> pii;typedef vector<int> vi;typedef vector<int>::iterator vit;struct edge { int u, v, c;//复习下自定义比较器,下面是按从大到小进行排序时用到的比较器 friend bool operator < (const edge &a, const edge &b) { return a.c > b.c; }} arr[MAXM]; //边的集合int parent[MAXN];//保存并查集中每一个结点的树根bool circled[MAXN];//标记连通分量是否存在环//包括并查集的初始化和无环的初始化void init (int n) {for (int i = 0; i < n; ++i) {parent[i] = i;circled[i] = false;}}//并查集找树根,路径压缩int find (int x) {int i = x, r;while (parent[x] != x)x = parent[x];r = x;while (i != r) {x = parent[i];parent[i] = r;i = x;}return r;}int main () {int n, m, fa, fb, ans;while (scanf("%d%d", &n, &m), n || m) {for (int i = 0; i < m; ++i)scanf("%d%d%d", &arr[i].u, &arr[i].v, &arr[i].c);sort (arr, arr + m); //对所有的边按权值从大到小进行排序init (n);ans = 0;for (int i = 0; i < m; ++i) {fa = find (arr[i].u);fb = find (arr[i].v);if (fa == fb) {//该边的两个端点属于同一个连通分量if (circled[fa])//连通分量已存在环continue;circled[fa] = true;//标记连通分量成环ans += arr[i].c;//更新伪森林的值} else {//该边的两个端点不属于同一个连通分量if (circled[fa] && circled[fb])//两个连通分量都已存在环continue;parent[fa] = fb;//并查集合并circled[fb] = circled[fb] || circled[fa]; //合并后的连通分量是否存在环ans += arr[i].c;//更新伪森林的值}}printf("%d\n", ans);}return 0;}
- HDU 3367 Pseudoforest (最小生成树,并查集)
- HDU 3367 Pseudoforest 最小生成树、并查集
- HDU 3367 Pseudoforest(最大生成树+并查集)
- Hdu 3367 Pseudoforest(并查集)
- hdu 3367 Pseudoforest (并查集)
- HDU 3367 Pseudoforest (并查集)
- hdu-3367-Pseudoforest-并查集
- HDU 3367 Pseudoforest 最小生成树
- HDU 3367 Pseudoforest(伪森林)(并查集)
- hdu 3367 Pseudoforest kruskal算法的变种+并查集
- hdu 3367 Pseudoforest(最大生成树)
- HDU 1232(最小生成树;并查集)
- 并查集+最小生成树(贪心)HDU 1879
- hdu 2682 Tree 最小生成树 (并查集)
- HDU 5253 最小生成树(kruskal)+ 并查集
- hdoj 3367 Pseudoforest 【伪森林】 【并查集判断环 + 最大生成树】
- HDOJ 题目3367 Pseudoforest(并查集)
- hdoj 3367 Pseudoforest(并查集)
- Java的值传递与引用传递
- maven Nexus入门指南(图文)
- Java Service Wrapper工具把Java程序转换为Windows服务小结(新版3.5.17)
- android WIFI连接开发
- Excel是最常用的办公软件。每个单元格都有唯一的地址表示。 比如:第4列表示为:“D”,第255列表示为“IU”。 事实上,Excel提供了两种地址表示方法,还有一种表示法叫做RC格式地址。
- HDU 3367 Pseudoforest (最小生成树,并查集)
- kaptcha验证码使用
- Apache的简单配置
- QueryServiceStatus、SetServiceStatus:获取设置服务运行状态
- (方法二)Excel是最常用的办公软件。每个单元格都有唯一的地址表示 比如:第4列表示为:“D”,第255列表示为“IU”。 事实上,Excel提供了两种地址表示方法,还有一种表示法叫做R
- Row Exclusive Table Lock (RX)
- python httplib库简介。。。
- SMS的源码研究
- java中的值传递和引用传递