图论(六)--最小生成树
来源:互联网 发布:数据库字段唯一性约束 编辑:程序博客网 时间:2024/05/28 11:50
基于算法导论图算法-最小生成树(第23章)
- 题目描述
- 问题分析
- 源代码
- 结果截图
题目描述
分别使用Kruskal算法和Prime算法求最小生成树(无向图)
问题分析
源代码
const int MAXN = 110;//最大点数const int MAXM = 10000;//最大边数struct Edge { int u, v, w;};//const int INF = 0x3f3f3f3f;//已经在Graph.h中定义void init_G(Graph G);//将图的链表表示改为矩阵表示int kruskal(int n);//返回最小生成树的权值,如果不联通返回-1,最小生成树的边集存入到数组vis_edge中int Prim_matrix(int cost[][MAXN], int n);//图的矩阵形式primeint Prim(Graph G);//图的链表形式的primevoid print_minTree();
#include<algorithm>struct Edge graph_edge[MAXM];//存储边的信息,包括起点终点和权值int Graph_edgeNum;//图的边数,用于排序struct Edge minT_edge[MAXN];//记录最小生成树的边集int minT_edgeNum;//最小生成树边数,加边前赋值0//并查集使用int father[MAXN];int _rank[MAXN];void Make_Set(int n) {//将每个点独立 for (int i = 0; i < n; i++) { father[i] = i; _rank[i] = 0; }}int find(int n) {//找根 if (n != father[n]) father[n] = find(father[n]); //路径压缩 return father[n];}void Union(int x, int y) {//联合 x = find(x); y = find(y); if (_rank[x] > _rank[y]) father[y] = x; else if (_rank[y] > _rank[x]) father[x] = y; else { father[x] = y; _rank[y]++; }}void addedge(Edge* tempEdge ,int u, int v, int w , int edge_count)//添边{ tempEdge[edge_count].u = u; tempEdge[edge_count].v = v; tempEdge[edge_count].w = w;}bool cmp(Edge a, Edge b) {//排序,从小到大按照权值进行排序,用于kruskal return a.w < b.w;}int cost[MAXN][MAXN];//用于prime_matrixint pre[MAXN];//用于prime_matrixvoid init_G(Graph G) {//将图的链表表示改为矩阵表示 //将图的链表表示改为矩阵表示(prime_matrix的初始化) PtrToNode ptr; for (int i = 0; i < G->vexnum; i++) { for (int j = 0; j < G->vexnum; j++) { cost[i][j] = INF; } for (ptr = G->vertices[i].adjto; ptr != NULL; ptr = ptr->next) { cost[i][ptr->adjvex] = ptr->weight; } cost[i][i] = 0; } //将无向图转变为无向边的集合,kruskal的初始化 for (int i = 0; i < G->vexnum; i++) { for (int j = i + 1; j < G->vexnum; j++) { if (cost[i][j]!=INF) { addedge(graph_edge, i, j, cost[i][j], Graph_edgeNum++); } } }}int kruskal(int n) {/////////////////////////init();//初始化图的边集(可以通过用户输入的方式) //n为图顶点数,graph_edge为图的边集,以下进行kruskal Make_Set(n); sort(graph_edge, graph_edge+Graph_edgeNum, cmp); int minT_weight = 0;//权值初始为0 minT_edgeNum = 0; for (int i = 0; i < Graph_edgeNum; i++) { int u = graph_edge[i].u; int v = graph_edge[i].v; int w = graph_edge[i].w; int t1 = find(u); int t2 = find(v); if (t1 != t2) { minT_weight += w; addedge(minT_edge, u, v, w, minT_edgeNum++); Union(u, v); } if (minT_edgeNum == n - 1) break;//如果选择的边够了顶点数-1,则不用再判断其他边 } if (minT_edgeNum < n - 1) return -1;//如果图不联通,则达不到n-1 else return minT_weight;}bool vis[MAXN];//记录顶点是否已经选入最小生成树int lowWeight[MAXN];//保存正在建立的最小生成树到各顶点的权int Prim_matrix(int cost[][MAXN], int n)//点是0~n-1{ //////////////////////////////////init1();//初始化权矩阵,可以用户输入 int minT_weight = 0; memset(vis, false, sizeof(vis)); vis[0] = true;//选择第一个点为顶点0 printf("矩阵表示图prime选择点的顺序为:0 "); //刚开始最小生成树仅包含起始顶点0,所以lowWeight[i]即从顶点0到其他顶点的权(除有边连接的顶点外全部为无穷大) for (int i = 1; i < n; i++) { lowWeight[i] = cost[0][i]; pre[i] = 0; } minT_edgeNum = 0; for (int i = 1; i<n; i++) { int minWeight = INF; int nextVertex = -1; //选择出下一个顶点比较lowWeight,选出最小值(不包括已选择顶点) for (int j = 0; j<n; j++) if (!vis[j] && minWeight>lowWeight[j]) { minWeight = lowWeight[j]; nextVertex = j; } if (minWeight == INF)return -1;//原图不连通 minT_weight += minWeight;//最小生成树权值增加 vis[nextVertex] = true;//下一个顶点已选择 printf("%d ", nextVertex); addedge(minT_edge, pre[nextVertex], nextVertex, minWeight, minT_edgeNum++);//添加选择的边到最小生成树边集 //更新lowWeight[i]和pre[i],只需要比较新加入的顶点相邻的点即可 for (int j = 0; j<n; j++) if (!vis[j] && lowWeight[j]>cost[nextVertex][j]) { lowWeight[j] = cost[nextVertex][j]; pre[j] = nextVertex; } } printf("\n"); return minT_weight;}struct Qnode { int v; int key; Qnode(int _v = -1, int _key = -1) :v(_v), key(_key) {} bool operator<(const Qnode& x)const { return key > x.key;//这样优先队列建立小根堆 }};int Prim(Graph G)//点是0~n-1,算法思想与最短路dijkstra一致唯一不同的是松弛操作{ int s = 0;//第一个选择的点 int minT_weight = 0;//初始化权值为0 //初始化key和color(对应于prime_matrix中的lowWeight和vis数组) for (int i = 0; i < G->vexnum; i++) { G->vertices[i].key = INF; G->vertices[i].color = 0;//白色,未选入最小生成树 } G->vertices[s].key = 0; priority_queue<Qnode> Q; Q.push(Qnode(s, G->vertices[s].key)); Qnode temp; PtrToNode ptr; printf("链表表示图prime选择点的顺序为:"); while (!Q.empty()) { temp = Q.top(); Q.pop(); int u = temp.v; //下面两行是为了避免已经选入最小生成树的顶点再次进行计算 if (G->vertices[u].color) continue; G->vertices[u].color = 1;//黑色 minT_weight += G->vertices[u].key; printf("%d ",u); for (ptr = G->vertices[u].adjto; ptr!=NULL; ptr = ptr->next) { //relax松弛操作 if (!G->vertices[ptr->adjvex].color&&G->vertices[ptr->adjvex].key > ptr->weight) { G->vertices[ptr->adjvex].key = ptr->weight; G->vertices[ptr->adjvex].pred = u; Q.push(Qnode(ptr->adjvex, G->vertices[ptr->adjvex].key)); } } } //判断所有顶点是否全部选入最小生成树,如果没有证明不联通 int flag = 0; for (int i = 0; i < G->vexnum; i++) { if (!G->vertices[i].color) { flag = 1; break; } } printf("\n"); if (flag) return - 1; return minT_weight;}void print_minTree() { for (int i = 0; i < minT_edgeNum; i++) { printf("%d-%d 权值为:%d\n", minT_edge[i].u, minT_edge[i].v,minT_edge[i].w); }}int main() { //无向图的随机生成([图论(一)图的建立](http://blog.csdn.net/deep_kang/article/details/70877468)) CreateRandomUndirectGraph(); Graph G = CreateUndirectGraph(); printf("打印图结构:\n"); print_EdgeWeight(G); /*printf("\n下面是bfs:\n"); BFS(G, 0);*/ /*printf("\n下面是dfs:\n"); DFS(G);*/ /*printf("拓扑排序:\n"); if (topSort_queue(G)) { print_order_queue(G); topSort_dfs(G); print_order_dfs(G); } else { printf("失败,此图不满足有向无环图。\n"); }*/ //printf("\n求强连通分量:\n"); //strongly_connected_components(G); init_G(G);//将图的链表表示改为矩阵表示,并将无向边存入边集数组中,用于prime_matrix和kruskal int sumWeight = kruskal(G->vexnum); if (sumWeight != -1) { printf("kruskal最小生成树(边权和为%d):\n", sumWeight); print_minTree(); } else { printf("此图不连通\n"); } sumWeight = Prim(G); if (sumWeight != -1) { printf("Prim最小生成树(边权和为%d):\n", sumWeight); print_minTree(); } else { printf("此图不连通\n"); } extern int cost[MAXN][MAXN]; sumWeight = Prim_matrix(cost, G->vexnum); if (sumWeight != -1) { printf("Prim_matrix最小生成树(边权和为%d):\n", sumWeight); print_minTree(); } else { printf("此图不连通\n"); } return 0;}
结果截图
结果展示以9个顶点为例,三种方式结果一致。
0 0
- 图论(六)--最小生成树
- 编程练习六(最小生成树)
- 专题六-最小生成树
- 【图论】最小生成树
- 图论-最小生成树
- [kuangbin带你飞]专题六 最小生成树 (prim)(kruskal)(模板)
- HDU 1233 还是畅通工程 (kuangbin带你飞 专题六 最小生成树)
- hdu 1875 畅通工程再续(kuangbin带你飞 专题六:最小生成树)
- POJ 1287 Networking (kuangbin带你飞 专题六:最小生成树)
- POJ 2421 HDOJ 1102 Constructing Roads(kuangbin带你飞 专题六:最小生成树)
- POJ 1679 The Unique MST(kuangbin带你飞 专题六:最小生成树)
- POJ 2349&&ZOJ 1914 Arctic Network(kuangbin带你飞 专题六:最小生成树)
- ZOJ 1586&&FZU 1096 QS Network(kuangbin带你飞 专题六 最小生成树)
- POJ 1789 Truck History(kuangbin带你飞 专题六:最小生成树)
- POJ 1751 Highways(kuangbin带你飞 专题六:最小生成树)
- kuangbin带你飞 专题六 最小生成树 1586(基本都是水题)
- 【 题集 】 【kuangbin带你飞】专题六 最小生成树
- [kuangbin带你飞]专题六 最小生成树
- erlang web 小结
- 分布式项目中遇到的一些问题:记录
- Maven项目单元测试配置问题
- 深度学习中的batch、batch size与epoch
- PHP:JSON函数json_encode详解
- 图论(六)--最小生成树
- Storm与Spark streaming的比较
- MySQL修改root密码的多种方法
- Android使用Webview播放Swf文件,实现与Flash数据交互
- Android 关于prebuilt编译学习笔记
- python 读取utf-16时缺少字节的处理
- C/C++之回调函数
- Ubuntu 16.04 添加新用户及修改权限相关问题
- Spark-Streaming入门例子