POJ 2377 最大生成树

来源:互联网 发布:ansys14.5软件下载 编辑:程序博客网 时间:2024/05/22 22:00

问题描述: n个顶点,m条边,每条边有一个cost。 从m条边中选择若干条边使得n个顶点构成一颗树,要求cost的总和花费最大(最小)。

解决方案: kruskar算法生成最小生成树。关键点在于判断边的加入是否会引入环,环的检查使用并查集来实现,复杂度是O(lgN)。

算法的思想是贪心, 需要将输入的边按照cost从小到大排序,边的选择就是按照cost进行选择的。

#include<iostream>#include<algorithm>#include<fstream>using namespace std;//#define DEBUGstruct edge{int u;int v;int w;};bool cmp(const edge &a, const edge &b){return a.w > b.w;}static struct edge edges[20000];static int p[1001];static int num[1001];int findset(int x) /* 压缩路径 */{if (x != p[x])p[x] = findset(p[x]);return p[x];}int unionset(int s1, int s2)  /* 按照数量合并 */{if (s1 == s2)return -1;if (num[s1] > num[s2]){p[s2] = s1; num[s2] = 0;}else{p[s1] = s2; num[s1] = 0;}return 0;}int main(){#ifdef DEBUGfstream cin("G:\\book\\algorithms\\acm\\Debug\\dat.txt");#endifint n, m;cin >> n >> m;int i;for (i = 0; i < m; i++){cin >> edges[i].u >> edges[i].v >> edges[i].w;}sort(edges, edges + m, cmp);/* 降序排列 贪心*/for (i = 1; i <= n; i++){p[i] = i;num[i] = 1;}int cost = 0;int trees = n;for (i = 0; i < m; i++){int pu, pv;pu = findset(edges[i].u);pv = findset(edges[i].v);if (pv != pu) /* the edge connect different trees */{unionset(pv,pu);cost += edges[i].w;trees--;}}if (trees > 1)cout << -1 << "\n";else cout << cost << "\n"; return 0;}

使用最小生成树算法,理论分析见算法导论的23.2小节。 

基本的算法思想是贪心算法。对输入的边按照权重进行排序后依次处理,根据排序的方式决定是最大生成树还是最小生成树。

成树的过程中防止生成环, 采用并查集的方式进行检测。可以看出使用并查集后算法的过程就很简单了。复杂度是和边的数目有关的,

是否能够成树,即是否最终能够得到一个联通图,采用变量进行检测即可。

Kruskal算法对边进行操作,初始状态是n棵树构成的森林,通过边将各个树联通,构成一个无环的联通图

原创粉丝点击