本文主要是介绍HDU1879 继续畅通工程【Kruskal算法+并查集】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
继续畅通工程
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 26913 Accepted Submission(s): 11362
当N为0时输入结束。
问题描述:参见上文。
问题分析:
这是一个最小生成树的为问题,解决的算法有Kruskal(克鲁斯卡尔)算法和Prim(普里姆) 算法。
程序说明:
本程序使用Kruskal算法实现。有关最小生成树的问题,使用克鲁斯卡尔算法更具有优势,只需要对所有的边进行排序后处理一遍即可。程序中使用了并查集,用来判定加入一条边后会不会产生循环。程序中,图采用边列表的方式存储,按边的权从小到大顺序放在优先队列中,省去了排序。
代码不够简洁,又写了一个简洁版。
AC的C++语言程序(简洁版)如下:
/* HDU1879 继续畅通工程 */#include <iostream>
#include <queue>
#include <stdio.h>using namespace std;const int N = 100;
int f[N + 1];void UFInit(int n)
{for(int i = 1; i <=n; i++)f[i] = i;
}int Find(int a) {return a == f[a] ? a : f[a] = Find(f[a]);
}bool Union(int a, int b)
{a = Find(a);b = Find(b);if (a != b) {f[a] = b;return true;} elsereturn false;
}struct edge {int src, dest, cost;bool operator < (const edge& n) const {return cost > n.cost;}
};int main()
{int n, ecount, status;edge e;while(scanf("%d", &n) != EOF && n) {priority_queue<edge> q; // 优先队列,用于存储边列表UFInit(n);ecount = n * (n - 1) / 2;while(ecount--) {scanf("%d%d%d%d", &e.src, &e.dest, &e.cost, &status);if(status == 1)Union(e.src, e.dest);elseq.push(e);}// Kruskal算法:获得最小生成树int ans=0, count=0;while(!q.empty()) {e = q.top();q.pop();if(Union(e.src, e.dest)) {count++;ans += e.cost;}if(count == n - 1)break;}// 输出结果printf("%d\n", ans);}return 0;
}
AC的C++语言程序如下:
/* HDU1879 继续畅通工程 */#include <iostream>
#include <queue>
#include <cstdio>using namespace std;const int MAXN = 100;// 并查集
int v[MAXN+1];
class UF {
public:UF() {}// 压缩int Find(int x) {if(x == v[x])return x;elsereturn v[x] = Find(v[x]);}bool Union(int x, int y) {x = Find(x);y = Find(y);if(x == y)return false;else {v[x] = y;return true;}}void reset(int n) {for(int i=0; i<=n; i++)v[i] = i;}
};struct edge {int src, dest, cost;bool operator < (const edge& n) const {return cost > n.cost;}
};int main()
{int n, ecount, status;UF uf;edge e;while(scanf("%d", &n) != EOF && n) {priority_queue<edge> q; // 优先队列,用于存储边列表uf.reset(n);ecount = n * (n - 1) / 2;while(ecount--) {scanf("%d%d%d%d", &e.src, &e.dest, &e.cost, &status);if(status == 1)uf.Union(e.src, e.dest);elseq.push(e);}// Kruskal算法:获得最小生成树int ans=0, count=0;while(!q.empty()) {e = q.top();q.pop();if(uf.Union(e.src, e.dest)) {count++;ans += e.cost;}if(count == n - 1)break;}// 输出结果printf("%d\n", ans);}return 0;
}
这篇关于HDU1879 继续畅通工程【Kruskal算法+并查集】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!