图(Graph)——最小生成树、最短路径、Kruskal、Dijkstra、Floyd

4. 最小生成树

4.1 生成树

(1)定义:所有顶点均由边连接在一起,但不存在回路的图叫该图的生成树
(2)深度优先生成树与广度优先生成树

(3)

    一个图可以有许多棵不同的生成树
    所有生成树具有以下共同特点:
           生成树的顶点个数与图的顶点个数相同
           生成树是图的极小连通子图


4.2 最小生成树

生成树的每条边上的权值之和最小。

实例:在N个城市之间修路,总路线的总和最小问题。

4.2.1 Prim方法

设N=(V,{E})是连通网,TE是N上最小生成树中边的集合:
(1)初始令U={u0},(u0属于V), TE=NULL
(2)在所有u属于U,v属于V-U的边(u,v)属于E中,找一条代价最小的边(u0,v0)
(3)将(u0,v0)并入集合TE,同时v0并入U
(4)重复上述操作直至U=V为止,则T=(V,{TE})为N的最小生成树

4.2.2 Kruskal算法

设连通网N=(V,{E}),令最小生成树
(1)初始状态为只有n个顶点而无边的非连通图T=(V,{NULL}),每个顶点自成一个连通分量
(2)在E中选取代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边,选取下一条代价最小的边
(3)依此类推,直至T中所有顶点都在同一连通分量上为止


5.拓扑排序和 关键路径

5.1 拓扑排序

拓扑排序的基础:有向无环图,它是描述一项工程进度的有效工具。

5.1.1 AOV网

用顶点表示活动,用弧表示活动间优先关系的有向图称为顶点表示活动的网(Activity On Vertex network),简称AOV网

5.1.2 拓扑排序算法

(1)在有向图中选一个没有前驱的顶点且输出之
(2)从图中删除该顶点和所有以它为尾的弧
(3)重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止

5.2 关键路径

在AOV网中,完成工程的最短时间:从开始点到完成点的最长路径长度——关键路径。

Ve(j)——表示事件Vj的最早发生时间
Vl(j)——表示事件Vj的最迟发生时间
e(i)——表示活动ai的最早开始时间
l(i)——表示活动ai的最迟开始时间
l(i)-e(i)——表示完成活动ai的时间余量


6. 最短路径

最短路径:路径上所有边的权值之和最小。

6.1 某顶点到其它个点的最短路径

Dijkstra算法:

(1)初使时令 S={V0},T={其余顶点},T中顶点对应的距离值
(2)若存在<V0,Vi>,为<V0,Vi>弧上的权值
(3)若不存在<V0,Vi>,为无穷
(4)从T中选取一个其距离值为最小的顶点W,加入S
(5)对T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值比不加W的路径要短,则修改此距离值
(6)重复上述步骤,直到S中包含所有顶点,即S=V为止

6.2 每对顶点之间的最短路径

Floyd算法:

(1)初始时设置一个n阶方阵,令其对角线元素为0,若存在弧<Vi,Vj>,则对应元素为权值;否则为无穷
(2)逐步试着在原直接路径中增加中间顶点,若加入中间点后路径变短,则修改之;否则,维持原值
(3)所有顶点试探完毕,算法结束



  • 10
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Prim、KruskalFloydDijkstra算法的C语言代码,我可以为您提供一些示例。请注意,以下代码仅供参考,实际应用时可能需要根据具体情况进行调整。 1. Prim算法(最小生成树): ```c #include <stdio.h> #include <stdbool.h> #define INF 9999 #define V 5 int minKey(int key[], bool mstSet[]) { int min = INF, min_index; for (int v = 0; v < V; v++) { if (mstSet[v] == false && 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 \t%d \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] = INF; 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] == false && graph[u][v] < key[v]) { parent[v] = u; key[v] = graph[u][v]; } } } printMST(parent, graph); } int main() { 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; } ``` 2. Kruskal算法(最小生成树): ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define V 5 #define MAX_EDGES 10 struct Edge { int src, dest, weight; }; struct Graph { int V, E; struct Edge edges[MAX_EDGES]; }; struct Graph* createGraph(int V, int E) { struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph)); graph->V = V; graph->E = E; return graph; } int find(int parent[], int i) { if (parent[i] == -1) return i; return find(parent, parent[i]); } void Union(int parent[], int x, int y) { int xset = find(parent, x); int yset = find(parent, y); parent[xset] = yset; } int compare(const void* a, const void* b) { struct Edge* a1 = (struct Edge*)a; struct Edge* b1 = (struct Edge*)b; return a1->weight - b1->weight; } void kruskalMST(struct Graph* graph) { int parent[V]; int i, j; int edgeCount = 0; qsort(graph->edges, graph->E, sizeof(graph->edges[0]), compare); for (i = 0; i < V; i++) parent[i] = -1; i = 0; while (edgeCount < V - 1 && i < graph->E) { struct Edge nextEdge = graph->edges[i++]; int x = find(parent, nextEdge.src); int y = find(parent, nextEdge.dest); if (x != y) { printf("%d - %d\t%d\n", nextEdge.src, nextEdge.dest, nextEdge.weight); Union(parent, x, y); edgeCount++; } } } int main() { int V = 5; int E = 7; struct Graph* graph = createGraph(V, E); graph->edges[0].src = 0; graph->edges[0].dest = 1; graph->edges[0].weight = 2; graph->edges[1].src = 0; graph->edges[1].dest = 3; graph->edges[1].weight = 6; // 以此类推,添加其他边的信息... kruskalMST(graph); return 0; } ``` 3. Floyd算法(最短路径): ```c #include <stdio.h> #define V 4 #define INF 99999 void printSolution(int dist[][V]); void floydWarshall(int graph[][V]) { int dist[V][V], i, j, k; for (i = 0; i < V; i++) { for (j = 0; j < V; j++) { dist[i][j] = graph[i][j]; } } for (k = 0; k < V; k++) { for (i = 0; i < V; i++) { for (j = 0; j < V; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; } } } } printSolution(dist); } void printSolution(int dist[][V]) { printf("The following matrix shows the shortest distances between every pair of vertices:\n"); for (int i = 0; i < V; i++) { for (int j = 0; j < V; j++) { if (dist[i][j] == INF) { printf("%7s", "INF"); } else { printf("%7d", dist[i][j]); } } printf("\n"); } } int main() { int graph[V][V] = { {0, 5, INF, 10}, {INF, 0, 3, INF}, {INF, INF, 0, 1}, {INF, INF, INF, 0} }; floydWarshall(graph); return 0; } ``` 4. Dijkstra算法(最短路径): ```c #include <stdio.h> #include <stdbool.h> #define V 6 #define INF 9999 int minDistance(int dist[], bool sptSet[]) { int min = INF, min_index; for (int v = 0; v < V; v++) { if (sptSet[v] == false && dist[v] <= min) { min = dist[v]; min_index = v; } } return min_index; } void printSolution(int dist[]) { printf("Vertex \t\t Distance from Source\n"); for (int i = 0; i < V; i++) { printf("%d \t\t %d\n", i, dist[i]); } } void dijkstra(int graph[V][V], int src) { int dist[V]; bool sptSet[V]; for (int i = 0; i < V; i++) { dist[i] = INF; sptSet[i] = false; } dist[src] = 0; for (int count = 0; count < V - 1; count++) { int u = minDistance(dist, sptSet); sptSet[u] = true; for (int v = 0; v < V; v++) { if (!sptSet[v] && graph[u][v] && dist[u] != INF && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; } } } printSolution(dist); } int main() { int graph[V][V] = { {0, 4, 0, 0, 0, 0}, {4, 0, 8, 0, 0, 0}, {0, 8, 0, 7, 0, 4}, {0, 0, 7, 0, 9, 14}, {0, 0, 0, 9, 0, 10}, {0, 0, 4, 14, 10, 0} }; dijkstra(graph, 0); return 0; } ``` 以上是Prim、KruskalFloydDijkstra算法的一些示例C语言代码。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值