图论算法详解(C++版)
prim算法求最小生成树c代码

一、概述在图论中,最小生成树是指在一个连通图中生成一棵包含图中所有顶点且边权值之和最小的树。
prim算法是一种常用的求取最小生成树的算法之一,其基本思想是从一个起始顶点开始,逐步选择与当前树相邻的并且权值最小的边,直到包含了图中所有的顶点为止。
本文将介绍prim算法的原理以及给出相应的C代码实现。
二、prim算法原理1. 初始化选择任意一个顶点作为起始顶点,并将其标记为已访问。
设置一个集合V来存放已经访问的顶点,初始化为空集合。
2. 重复以下步骤直到V包含了所有顶点:(1)遍历集合V中的所有顶点,找到与之相邻且未被访问过的顶点中边权值最小的顶点,将其加入集合V中。
(2)将找到的顶点与其相邻的边加入最小生成树中。
3. 输出最小生成树当集合V包含了所有顶点之后,即可输出最小生成树。
三、prim算法C代码实现以下是prim算法的C代码实现:#include <stdio.h>#include <limits.h>#define V 5 // 顶点个数int minKey(int key[], bool mstSet[]) {int min = INT_MAX, min_index;for (int v = 0; v < V; v++) {if (!mstSet[v] key[v] < min) {min = key[v], min_index = v;}}return min_index;}void printMST(int parent[], int graph[V][V]) {printf("Edge \tWeight\n");for (int i = 1; i < V; i++) {printf("d - d \td \n", parent[i], i, graph[i][parent[i]]);}void primMST(int graph[V][V]) {int parent[V]; // 存放最小生成树的结点int key[V]; // 存放与最小生成树相邻的边的权值bool mstSet[V]; // 存放已访问的顶点for (int i = 0; i < V; i++) {key[i] = INT_MAX, mstSet[i] = false;}key[0] = 0;parent[0] = -1;for (int count = 0; count < V - 1; count++) {int u = minKey(key, mstSet);mstSet[u] = true;for (int v = 0; v < V; v++) {if (graph[u][v] !mstSet[v] graph[u][v] < key[v]) { parent[v] = u, key[v] = graph[u][v];}}}printMST(parent, graph); }int m本人n() {int graph[V][V] = {{0, 2, 0, 6, 0},{2, 0, 3, 8, 5},{0, 3, 0, 0, 7},{6, 8, 0, 0, 9},{0, 5, 7, 9, 0}};primMST(graph);return 0;}```四、代码说明1. minKey函数该函数用于在尚未加入最小生成树的结点中找到与最小生成树相邻的边中权值最小的结点。
图论中的常用经典算法

图论中的常用经典算法第一节最小生成树算法一、生成树的概念若图是连通的无向图或强连通的有向图,则从其中任一个顶点出发调用一次bfs或dfs后便可以系统地访问图中所有顶点;若图是有根的有向图,则从根出发通过调用一次dfs或bfs亦可系统地访问所有顶点。
在这种情况下,图中所有顶点加上遍历过程中经过的边所构成的子图称为原图的生成树。
对于不连通的无向图和不是强连通的有向图,若有根或者从根外的任意顶点出发,调用一次bfs或dfs后不能系统地访问所有顶点,而只能得到以出发点为根的连通分支(或强连通分支)的生成树。
要访问其它顶点则还需要从没有访问过的顶点中找一个顶点作为起始点,再次调用bfs 或dfs,这样得到的是生成森林。
由此可以看出,一个图的生成树是不唯一的,不同的搜索方法可以得到不同的生成树,即使是同一种搜索方法,出发点不同亦可导致不同的生成树。
如下图:但不管如何,我们都可以证明:具有n个顶点的带权连通图,其对应的生成树有n-1条边。
二、求图的最小生成树算法严格来说,如果图G=(V,E)是一个连通的无向图,则把它的全部顶点V和一部分边E’构成一个子图G’,即G’=(V, E’),且边集E’能将图中所有顶点连通又不形成回路,则称子图G’是图G的一棵生成树。
对于加权连通图,生成树的权即为生成树中所有边上的权值总和,权值最小的生成树称为图的最小生成树。
求图的最小生成树具有很高的实际应用价值,比如下面的这个例题。
例1、城市公交网[问题描述]有一张城市地图,图中的顶点为城市,无向边代表两个城市间的连通关系,边上的权为在这两个城市之间修建高速公路的造价,研究后发现,这个地图有一个特点,即任一对城市都是连通的。
现在的问题是,要修建若干高速公路把所有城市联系起来,问如何设计可使得工程的总造价最少。
[输入]n(城市数,1<=n<=100)e(边数)以下e行,每行3个数i,j,w ij,表示在城市i,j之间修建高速公路的造价。
图论中的最短路径算法

图论中的最短路径算法图论是数学的一个分支,研究图的性质和图之间的关系。
在图论中,最短路径算法是一类重要的算法,用于寻找图中两个顶点之间的最短路径。
本文将介绍图论中的几种常见的最短路径算法。
一、Dijkstra算法Dijkstra算法是最短路径算法中最常用的一种。
它基于贪心策略,通过逐步扩展路径来求解最短路径。
算法的基本思想是,从一个起始顶点开始,逐步扩展到其他顶点,每次选择当前路径中距离起始顶点最近的顶点进行扩展,直到扩展到目标顶点或者所有顶点都被扩展完毕。
Dijkstra算法的步骤如下:1. 初始化起始顶点的距离为0,其他顶点的距离为无穷大。
2. 选择距离起始顶点最近的顶点,将其加入已扩展顶点集合。
3. 更新与新加入顶点相邻的顶点的距离,如果新的距离比原来的距离小,则更新距离。
4. 重复步骤2和步骤3,直到扩展到目标顶点或者所有顶点都被扩展完毕。
5. 根据更新后的距离,可以得到最短路径。
二、Bellman-Ford算法Bellman-Ford算法是另一种常用的最短路径算法。
它可以处理带有负权边的图,而Dijkstra算法只适用于非负权边的图。
Bellman-Ford算法的基本思想是通过对所有边进行松弛操作,逐步减小起始顶点到其他顶点的估计距离,直到得到最短路径。
Bellman-Ford算法的步骤如下:1. 初始化起始顶点的距离为0,其他顶点的距离为无穷大。
2. 对所有边进行松弛操作,即如果存在一条边(u, v),使得从起始顶点到v的距离大于从起始顶点到u的距离加上边(u, v)的权值,则更新距离。
3. 重复步骤2,直到没有顶点的距离发生变化。
4. 根据更新后的距离,可以得到最短路径。
三、Floyd-Warshall算法Floyd-Warshall算法是一种多源最短路径算法,可以求解图中任意两个顶点之间的最短路径。
该算法通过动态规划的方式,逐步更新顶点之间的距离,直到得到最短路径。
Floyd-Warshall算法的步骤如下:1. 初始化顶点之间的距离矩阵,如果两个顶点之间存在边,则距离为边的权值,否则距离为无穷大。
哈密尔顿环 c算法

哈密尔顿环c算法全文共四篇示例,供读者参考第一篇示例:哈密尔顿环(Hamiltonian cycle)是图论中一个重要的概念,指的是图G中一条包含所有顶点且恰好经过一次的环。
哈密尔顿环问题是一个NP难题,即目前尚未找到有效的多项式时间算法来解决该问题。
寻找哈密尔顿环的有效算法一直是图论领域的热门研究方向之一。
在图论中,哈密尔顿环的存在性和性质一直备受关注。
给定一个图G,如果存在一个哈密尔顿环,那么这个图被称为哈密尔顿图;如果不存在哈密尔顿环,但是对于图中的任意两个不同的顶点u和v,存在经过这两个顶点的哈密尔顿路径(即包含u和v并且其余顶点均不重复的路径),则称之为哈密尔顿连通图。
哈密尔顿图和哈密尔顿连通图是图论中两个非常重要的概念,它们的研究对于理解各种应用问题具有重要的意义。
现在我们来介绍一种经典的哈密尔顿环算法——C算法。
C算法是一种基于回溯思想的搜索算法,它通过递归地搜索图中的所有可能的路径来找到哈密尔顿环。
虽然C算法在最坏情况下可能需要指数级的时间复杂度来解决哈密尔顿环问题,但是在实际应用中,它仍然是一种较为有效的方法。
C算法的基本思想是从图中的任意一个顶点开始,逐步向下一个未访问的顶点移动,并判断是否满足环的条件。
在搜索过程中,如果无法找到符合条件的路径,则回退到上一个节点,继续向其他未访问过的节点探索。
通过递归的方式,C算法最终可以找到所有可能的哈密尔顿环。
在实际应用中,C算法通常需要配合一些剪枝策略来提高搜索效率。
在搜索过程中,可以根据一些启发式规则来减少搜索空间,从而快速排除不可能存在哈密尔顿环的路径。
还可以利用一些局部优化技巧,如动态规划、记忆化搜索等,来加速查找哈密尔顿环的速度。
虽然C算法在最坏情况下的时间复杂度较高,但在实际应用中,它仍然是一种可行的方法。
通过合理设计剪枝策略和优化技巧,我们可以提高C算法的搜索效率,从而更快地找到哈密尔顿环。
在解决具体问题时,我们可以根据实际情况选择不同的搜索策略和优化方法,以达到更好的效果。
图论的基本算法

0 6 8
A
3 4
0
7 0 5
2 0
无向图G的权矩阵A是一个对称矩阵.
0 6 3 4
A
6 3 4
0 7
7 0 2
2 0
关联矩阵
1, 若vi是ej的始点; aij 1, 若vi是ej的终点;
0, 若vi与ej不关联.
有向图的关联矩阵每列的元素中有且仅有一个1,有且仅有一 个 - 1.
有向的情形
入度 = 出度 如何套圈?
道路
有两个奇度点 正好是起点和终点
哪个是起点,哪个是终点?
有向+无向怎么办?
网络流!不要求掌握
幼儿园的粉刷
幼儿园里有很多房屋
房屋与房屋之间连以走廊 走廊与房屋之间有一扇门 幼儿园长想把门漆成绿色或者黄色,使得
任意一条走廊两头门的颜色不同 任意一间房屋上的门,绿色门的数量与黄色门的数量相差不超
所有K值加起来,除以2(每一针有两个端点)
最小生成树问题
求一个连通子图,使得边权和最小
Prim算法
任意时刻的中间结果都是一棵树
从一个点开始 每次都花最小的代价,用一条加进一个新点
问题:
这样做是对的吗? 如何快速找到这个“最小代价”?
Prim算法的正确性
换一种说法
如果存在一个MST,包含当前所有边 则也存在一个 MST, 它包含最小代价边(u, v)
如果添加之后S仍是独立集,则添加成功 如果S不是独立集,则由定义知以后无论怎样继续添加元素,
得到的集合都不可能重新成为独立集,因此撤消此添加操作。
A1 A6 A3 A7 A2 A8 A5 A10; A1 A6 A3 A9 A4 A8 A5 A10.
图论算法(C版)

•
int circuit[maxn];
//用来记录找到的欧拉路的路径
•
int n,e,circuitpos,i,j,x,y,start;
•
void find_circuit(int i)
//这个点深度优先遍历过程寻找欧拉路
•
{
•
int j;
•
for (j = 1; j <= n; j++)
•
if (g[i][j] == 1)
•}
• 主程序如下:
• int main()
•{
• ……
• memset(visited,false,sizeof(visited));
• for (int i = 1; i <= n; i++)
//每一个点都作为起点尝试访问,因为不是从任何
•
//一点开始都能遍历整个图的,例如下面的两个图。
•
if (!visited[i])
• (b)无向图:图的边没有方向,可以双向。(b)就是一个无向图。
1
1
• 结点的度:无向图中与结点相连的边的数目,称为结点的度。 5
25
2
• 结点的入度:在有向图中,以这个结点为终点的有向边的数目。 4
• 结点的出度:在有向图中,以这个结点为起点的有向边的数目。
3
43
• 权值:边的“费用”,可以形象地理解为边的长度。
•
}
•
…………
•
return 0;
•}
• 建立邻接矩阵时,有两个小技巧:
•
初始化数组大可不必使用两重for循环。
•
1) 如果是int数组,采用memset(g, 0x7f, sizeof(g))可全部初始化为一个很大的数(略小于0x7fffffff),使用
c++ 遍历所有点且距离最短_最短路径问题dijkstra算法详解
c++ 遍历所有点且距离最短_最短路径问题dijkstra算法详解一、问题概述在图论中,最短路径问题是一个重要的研究课题,它涉及到从一个节点到另一个节点的最短路径的寻找。
Dijkstra算法是一种用于解决最短路径问题的经典算法,它可以高效地遍历图中的所有节点,并找到从起始节点到目标节点的最短路径。
二、Dijkstra算法详解1. 算法思想Dijkstra算法的基本思想是:对于图中的每个节点,选择距离起始节点最近的节点,并将其标记为已访问。
然后,从已访问的节点中选择下一个距离起始节点最近的节点,并将其标记为已访问。
重复这个过程,直到遍历完所有的节点。
在每一步中,算法都会更新节点之间的距离信息,以使得结果更加精确。
2. 算法步骤(1) 初始化:将起始节点的距离设置为0,将所有其他节点的距离设置为无穷大。
将起始节点标记为已访问。
(2) 遍历所有相邻节点:对于每个已访问的节点,遍历其所有相邻节点,并更新它们到起始节点的距离。
对于每个相邻节点,如果通过该相邻节点到达起始节点的距离比当前距离更短,则更新该相邻节点的距离。
(3) 终止条件:当没有未访问的节点时,算法终止。
此时,每个节点的最短路径已经确定。
3. C语言实现以下是一个简单的C语言实现Dijkstra算法的示例代码:```c#include <stdio.h>#include <stdlib.h>#define MAX_VERTICES (100) // 最大顶点数int minDistance[MAX_VERTICES]; // 存储最小距离的数组int dist[MAX_VERTICES]; // 存储每个节点到起点的实际距离的数组bool visited[MAX_VERTICES]; // 标记每个节点是否已访问的数组int src; // 起点int V; // 顶点数void dijkstra(int G[MAX_VERTIXE][MAX_VERTICES], int src) {V = G[0].size(); // 获取顶点数for (int i = 0; i < V; i++) {dist[i] = INT_MAX; // 初始化所有顶点到起点的距离为无穷大visited[i] = false; // 所有顶点未访问}dist[src] = 0; // 起点的距离为0for (int count = 0; count < V - 1; count++) {int u = vertex_selection(G, dist, visited); // 选择当前距离最小的顶点uvisited[u] = true; // 将u标记为已访问for (int v = 0; v < V; v++) { // 遍历u的所有邻居顶点if (!visited[v] && (dist[v] > dist[u] + G[u][v])) { // 如果未访问且通过u到达v的距离更短dist[v] = dist[u] + G[u][v]; // 更新v的距离信息}}}}int vertex_selection(int G[MAX_VERTICES][MAX_VERTICES], int dist[], bool visited[]) {int minIdx = 0, minDist = INT_MAX;for (int v = 0; v < V; v++) { // 遍历所有顶点vif (!visited[v] && minDist > dist[v]) { // 如果未访问且当前距离更短minDist = dist[v];minIdx = v; // 记录最小距离和对应的顶点索引}}return minIdx; // 返回最小距离对应的顶点索引}```三、应用场景与优化方法Dijkstra算法适用于具有稀疏权重的图,它可以高效地找到最短路径。
图论
• •
解题思路
•
• •
但是这个方法点数是平方级别的,本题明显不足。
想法2: 把边变成点,点变成边,从一条边走向另一条边的代价是这 两条边的权值的较大值。
v1 v2
•
点数变为O(n)级别,但是对于菊花图, 边数仍是n^2级别的。
max(v1,v2)
解题思路
•
•
想法3:
对想法2进行优化,利用边权差来节省边数。具体的是对于连 接某一个点的所有边按边权排序,每条边在新图对应的点向 相邻的较大的边对应的点连一条权值为两条边的权值差的边, 向相邻的较小的边连一条权值为0的边,并且把这条边对应的 点拆成两个点,经过代价为这条边的权值。 这样就把max操作通过差分把边数优化成了O(m)级。
• •
•
Tax
• 给出一个N个点M条边的无向图,经过一个点的代价
是进入和离开这个点的两条边的边权的较大值,求从 起点1到点N的最小代价。起点的代价是离开起点的 边的边权,终点的代价是进入终点的边的边权
• N<=100000 • M<=200000
解题思路
•
•
如果n<=100
可以用分层图的思想,把每个点i拆成n个点,dist[i, j] 表示: 从起点出发,最终到达点i,且到达i的前一个点是j的最短距 离。(j的代价不算在内) [i1,j1]->[i2,i1]的边权为max(v[j1,i1], v[i1, i2]) 最后枚举i取min(dist[final, i] + v[i, final])作为答案
• •
解题思路
•
最开始的想法:
之间把每个点抽象成图中的节点,四联通连边,跑最短路?
不能考虑到起始的速度。
图论算法介绍
if (a[i,k]=1)and (a[k,j]=1) then a[i,j]=1 (a[i,j]=1表示i可达j,a[i,j]=0表示i不可达j)。
var
link,longlink:array[1..20,1..20] of boolean;{ 无向图和无向图的传递闭包。其
中
l o n g l i n k[i,
例如:公路交通图,边以距离w为权。
例
2
2
1
3
1
3
有向完全图 例
245
无向完全图 5
1
例 1
3
6
图与子图
57
32
46
G2
顶点5的度:3 顶点2的度:4
3
6
例 245
1
3
6
G1
顶点2入度:1 出度:3 顶点4入度:1 出度:0
例
路径:1,2,3,5,6,3 路径长度:5
245
简单路径:1,2,3,5
❖ 图 G = (V, E)
V = 顶点集 E = 边集 = V V的子集
结点集V={a, b, c, d} 边集E={e1, e2, e3, e4, e5} 其中e1=(a, b), e2=(a, c),
e3=(a, d), e4=(b, c), e5=(c, d)。
(一)、计算无向图的传递闭包
v1→v2→v4→v8→v5 →v3→v6→v7
算法结构:
调用一次dfs(i), 可按深度优先搜索 的顺序访问处理结 点i所在的连通分 支(或强连通分 支),dfs(i)的时 间复杂度为W(n2)。 整个图按深度优先 搜索顺序遍历的过 程如下:
显然,为了避免重复访问同一个顶点,必须 记住每个顶点是否被访问过。为此,可设置 一个布尔向量visited[1..n],它的初值为 false,一旦访问了顶点vi,便将visited[i] 置为ture。 图的深度优先搜索是一个递归过程,可以使 用栈来存储那些暂时不访问的邻接点.类似于 树的前序遍历,它的特点是尽可能先对纵深 方向进行搜索,故称之深度优先搜索。
与图论相关的算法
广度优先搜索
procedure bfs(i:integer); var p:arcptr;
closed,open:integer; q:array[1..maxn] of integer; begin 访问并处理顶点i; map[i].visited:=true; 顶点i进入队列q; closed:=0; open:=1; repeat
编号都不超过k的路径。 递推公式:
t(k)[i,j]= t(k-1)[i,j] or (t(k-1)[i,k] and t(k-1)[k,j])
Johnson算法
Johnson算法常用于求顶点个数较多的稀 疏图的每对点间最短路问题。
感兴趣的同学请参阅《国际信息学奥林 匹克竞赛指导——实用算法的分析与程 序设计》
inc(closed); v:=q[closed]; p:=map[v].firstarc; while p<>nil do begin
if map[p^.v].visited=false then begin 访问并处理顶点q^.v; map[q^.v].visited=true; inc(open); q[open]:=q^.v; end;
q:=q^.nextarc; end; until closed=open; end;
计算连通分支数
count:=0; for i:=1 to n do
map[i].visited:=false; for i:=1 to n do
if map[i].visited=false do begin inc(count); dfs(i); end;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.1、prim算法:无向图的生成树就是从图的边集中选择一些边,使得这些边构成一个连通无环图,也就是树。
如果给每一条边加一个权,所有生成树中权和最小的生成树称为最小生成树。
【Prim算法思想】任意时刻的中间结果都是一棵树,每次花费最小的代价,用一条边把不在树中的结点加进来。
【最小生成树算法实例】现有一张城市地图,图中的顶点为城市,无向边代表两个城市间的连通关系,边上的权代表公路造价。
在分析了这张图后发现,任一对城市都是连通的。
现在要求用公路把所有城市联系起来,如何设计可使得工程的总造价最少?【输入】第一行两个数v(v<=200),e,分别代表城市数和边数以下e行,每行为两个顶点和它们之间的边权w(w<1000)。
【输出】连通所有城市的公路最小造价。
【输入样例】6 101 2 101 5 191 6 212 3 52 4 62 6 113 4 64 5 184 6 145 6 33【输出样例】50 原图最小生成树#include<cstdio>#include<string>#include<cstring>#include<climits>using namespace std;int i,j,k,n,m,mi,t,s,a[1000][1000]; void prim(){int mi,p,f,k,d[1000];bool v[1000];memset(v,false,sizeof(v));f=1;for (i=2;i<=n;i++){d[i]=INT_MAX;}d[f]=0;s=0;for(i=1;i<=n;i++){mi=INT_MAX;for (j=1;j<=n;j++)if ((v[j]==false) && (d[j]<mi)){p=j;mi=d[j];}s+=mi;v[p]=true;for(j=1;j<=n;j++){if (a[p][j]<d[j]) d[j]=a[p][j];}}}int main(){memset(a,0,sizeof(a));scanf("%d%d",&n,&m);mi=INT_MAX;for (i=1;i<=n;i++){for (j=1;j<=n;j++){a[i][j]=INT_MAX;}}for (i=1;i<=m;i++){scanf("%d%d%d",&k,&j,&t);if ((t<a[k][j])||(t<a[j][k])){a[k][j]=t;a[j][k]=a[k][j];}}prim();printf("%d",s);return 0;}1.2、克鲁斯卡尔算法假设N=(V,{E})是连通网,将N中的边按权值从小到大的顺序排列;①、将n个顶点看成n个集合;②、按权值小到大的顺序选择边,所选边应满足两个顶点不在同一个顶点集合内,将该边放到生成树边的集合中。
同时将该边的两个顶点所在的顶点集合合并;③、重复②直到所有的顶点都在同一个顶点集合内。
可以看出,克鲁斯卡尔算法逐步增加生成树的边,与普利姆算法相比,可称为“加边法”。
假设G=(V,E) 是一个具有n个顶点的连通网,T=(U,TE)是G的最小生成树,U的初值等于V,即包含有G中的全部顶点,TE的初值为空集。
该算法的基本思想是:将图G中的边按权值从小到大的顺序依次选取,若选取的边使生成树T不形成回路,则把它并入TE中,保留作为T的一条边,若选取的边使生成树T形成回路,则将其舍弃,如此进行下去直到TE中包含n-1条边为止,此时的T即为最小生成树。
输入样例:6 101 3 11 4 53 4 54 6 23 6 45 6 63 5 62 3 52 5 31 2 6输出样例:50【算法思想】这是一种贪心法。
要使生成树最小,可以再每次都在剩余边中挑选最小的边加入生成树,直到所有顶点都在生成树中。
要实现这一目的,要解决三个问题。
首先,要对所有边按权从小到大排序,我们可以选用快排等高效率排序算法达到这一目的。
其次,要淘汰一些边。
即使它们的权很小,但在生成树中它们是多余的。
这里我们可以用并查集来解决。
每选取一条边,我们就把这条边的两个顶点放进同一个连通分量,通过一个能够寻找连通分量根结点的函数find(v)来判断。
如果find(v1)=find(v2),那么v1和v2已经属于同一连通分量,那么v1与v2间的边就不能再添加到生成树中。
第三,什么时候结束算法呢?可以设置一个计数器,当已经添加了n-1条边时,生成树就构造好了。
【程序】#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=100000+5;int m,n;struct data {int beg;int end;int fee;} a[maxn];int f[maxn];bool cmp(data a,data b){return a.fee<b.fee;}int getf(int v){if(f[v]==v)return v;//并查集找根节点?else{f[v]=getf(f[v]);//将一路上的节点直接连接到最终父节点?return f[v];}}void kruskal(){long long sum=0;int ans=0;for(int i=0; i<m&&ans<n; i++) {int x=getf(a[i].beg);int y=getf(a[i].end);if(x!=y) {sum+=a[i].fee;f[x]=y;ans++;}}printf("%lld\n",sum);}int main() {scanf("%d%d",&n,&m);for(int i=1; i<=n; i++) {f[i]=i;}for(int i=0; i<m; i++) {scanf("%d%d%d",&a[i].beg,&a[i].end,&a[i].fee);}sort(a,a+m,cmp);kruskal();return 0;}2、Dijkstra算法:设图G=(V,E)是一个有向图,它的每一条边(U,V)都有一个非负权W(U,V),在G中指定一个结点V0,要求从V0到G的每一个结点Vj的最短路径找出来(或指出不存在)。
由于源结点V0是给定的,所谓称为单源最短路径。
【Dijkstra算法思想】把所有结点分为两组。
第一组:包含已确定最短路径的结点。
第二组:包含尚未确定最短路径的结点。
按最短路径长度递增的顺序把第二组的结点加到第一组中去,直到V0可达的所有结点都包含于第一组中。
在这个过程中,总保持从V0到第一组各结点的最短路径长度都不大于从V0到第二组任何结点的路径长度。
【单源最短路径算法实例】现有一张县城的城镇地图,图中的顶点为城镇,无向边代表两个城镇间的连通关系,边上的权为公路造价,县城所在的城镇为v0。
由于该县经济比较落后,因此公路建设只能从县城开始规划。
规划的要求是所有可到达县城的城镇必须建设一条通往县城的汽车线路,该线路的工程总造价必须最少。
【输入】第一行一个整数v,代表城镇数,县城编号为1。
第二行是一个整数e,表示有向边数。
以下e行,每行为两个城镇编号和它们之间的公路造价。
【输出】v-1行,每行为两个城市的序号,表明这两个城市间建一条公路。
【输入样例】6 101 2 101 5 191 6 212 3 52 4 62 6 113 4 64 5 184 6 145 6 33【输出样例】1015161921原图从第1点出发的最短路径【程序】#include<cstdio>#include<cstdlib>#include<cstring>#define N 300using namespace std;const int MAXINT = 32767;const int MAXNUM = 10;int dist[MAXNUM];int prev[MAXNUM],n,m,i,j,k,p,t;int a[MAXNUM][MAXNUM];void dijk(int v0){bool s[MAXNUM]; // 判断是否已存入该点到S集合中for(int i=1; i<=n; ++i){dist[i] = a[v0][i];s[i] = false; // 初始都未用过该点if(dist[i] == MAXINT)prev[i] = -1;elseprev[i] = v0;}dist[v0]=0;s[v0]=true;for(int i=2; i<=n; i++){int mindist = MAXINT;int u=v0; // 找出当前未使用的点j的dist[j]最小值for(int j=1; j<=n; ++j)if((!s[j]) && dist[j]<mindist){u = j; // u保存当前邻接点中距离最小的点的号码mindist = dist[j];}s[u] = true;for(int j=1; j<=n; j++)if((!s[j]) && a[u][j]<MAXINT){if(dist[u] + a[u][j] < dist[j]) //在通过新加入的u点路径找到离v0点更短的路径{dist[j] = dist[u] + a[u][j]; //更新distprev[j] = u; //记录前驱顶点}}}}int main(){memset(a,0,sizeof(a));scanf("%d%d",&n,&m);for (i=1;i<=n;i++){for (j=1;j<=n;j++){a[i][j]=MAXINT;}}for (i=1;i<=m;i++){scanf("%d%d%d",&k,&p,&t);if ((t<a[k][p])||(t<a[p][k])){a[k][p]=t;a[p][k]=a[k][p];}}dijk(1);for (i=2;i<=n;i++) printf("%d\n", dist[i]);return 0;}3、Floyd算法:设图G=(V,E)是一个有向图,对于每对结点(U,V),找出从U到V的最短路径。