第6章 图的基本算法
来源:互联网 发布:志鸿优化设计历史答案 编辑:程序博客网 时间:2024/05/19 15:40
一、最小生成树和最短路径的区别
最小生成树是指生成树各边的权值总和最小的树,保证整体树的权值是最小,并不保证任意两点间的权值最小。
最短路径是保证从起始点到指定其余点的权值和最小,即求从起点到其余各点路径上权值和最小的路径。
二、3种主要算法实现
#if ! defined(MGRAPH_H)#define MGRAPH_H#include<limits.h>#include<stdio.h>#include<stdlib.h>#define MaxVertexNum 50typedef char VertexType;//顶点类型typedef int Adjmatrix;//边的权值typedef struct{VertexType vexs[MaxVertexNum];Adjmatrix arcs[MaxVertexNum][MaxVertexNum];//有边为指定数值,没有为INT_MAX}MGraph;/********Prim算法********基本思路:首先,选中指定1个顶点作为源点。然后,选择从该顶底到其余顶点中权值最小的点,并加入到源点中。再次,从源点中选择到其余顶点中权值最小的点。重复以上过程。*/typedef int VRType;//对应顶点在矩阵中的索引typedef enum{FREE,USED} State;//辅助顶点的状态typedef struct{ VertexType ver;//顶点类型 VRType lowcost;//边的权重 State used;//取值为FREE,USED}minedge;//从某个顶点到其余边的最小权重typedef minedge Edges[MaxVertexNum];//获取顶点在G中的下标int VtxNum(MGraph G,VertexType u,int n){ //G中有顶点和边的数组,u顶点,n顶点总数 int i; for(i=0;i<n;i++){ if(G.vexs[i]==u){ return i; } } return -1;}int minEdge(Edges edges,int n){//min是系统函数 //获取最小值 int i; int min=-1;//min是lowcost的最小值索引 int temp=0; int templowcost; for(i=0;i<n;i++){ if(edges[i].used==FREE){ if(temp==0){ //获取第一个最小值 temp=1; templowcost=edges[i].lowcost; min=i; }else if(temp==1){ //获取最小的 if(edges[i].lowcost<templowcost){ templowcost=edges[i].lowcost; min=i; }//end if }//end if } }//end for return min;}//获取void Prim(MGraph G,VertexType u,int n){ //G矩阵表,u起始顶点,n顶点总数 int k,v,j,pre; Edges edges;//定义辅助边数组 k=VtxNum(G,u,n);//获取顶点u在辅助数组中的位置 //辅助数组初始化 for(v=0;v<n;v++){ if(v!=k){ edges[v].ver=u;//各辅助数组记录各种点到u点的权重 edges[v].lowcost=G.arcs[k][v]; edges[v].used=FREE; }else{ //本节点 edges[v].lowcost=0; edges[v].used=USED; } } for(j=1;j<n;j++){ k=minEdge(edges,n);//k是u到其他点最小的权重边对应的点 //******显示******// printf("v%c-v%c\n",edges[k].ver,G.vexs[k]); edges[k].used=USED;//第k个顶点并入U for(v=0;v<n;v++){ if(edges[v].used==FREE && G.arcs[k][v]<edges[v].lowcost){ //各点到k节点,所在边的小权重 edges[v].ver=G.vexs[k]; edges[v].lowcost=G.arcs[k][v]; } }//end for }//end for}/*******Kruskal算法基本思路:选择最小的边,判断两个顶点是否已经在生成树中,若没有添加到生成树中;若已经在最小生成书中则放弃这条边。1.对边排序,按照。2.选择最小的边。3.判断边的两点是否已经在最小生成树中。4.重复2和3。*******/typedef struct{ int v1;//第一个顶点 int v2;//第二个顶点 int lowcost;//两点之间边的权重}Edge;//Kruskal辅助边算法typedef Edge KEdges[MaxVertexNum*MaxVertexNum];//辅助数组void KSort(KEdges KE,int n){ //对辅助数组排序 Edge e; int i,j,m=n*n; //直接插入排序算法 for(i=1;i<m;i++){ if(KE[i].lowcost<KE[i-1].lowcost){ e=KE[i]; j=i; do{ KE[j]=KE[j-1];//往后移位 j--; }while(j-1>=0 && e.lowcost<KE[j-1].lowcost );//这个条件和if的差不多 KE[j]=e; } }}void Kruskal(MGraph G,int n){ KEdges kedges;//辅助数组 int vectextag[MaxVertexNum]={0};//顶点出现次数标记 int i,j,k=0,m; //1.初始化辅助数组 for(i=0;i<n;i++){ for(j=0;j<n;j++){ kedges[k].v1=i; kedges[k].v2=j; kedges[k].lowcost=G.arcs[i][j]; k++; } }//end for //2.对边数组排序 KSort(kedges,n); //3.生成树 k=1;//用来标记相应顶点出现次数 m=n*n;//边的条数 for(i=0;i<m;i++){//不能简单适用i+=2于无向图,虽然因无向图边(i,j)和(j,i)的权值是相同的,但也有可能其他边的权值是相同的。 if(INT_MAX == kedges[i].lowcost) continue;//如果边是无穷大就不需要执行加入树的操作 if(0 == vectextag[kedges[i].v1] && 0== vectextag[kedges[i].v2]){ //新边两个新顶点 vectextag[kedges[i].v1]=k; vectextag[kedges[i].v2]=k; k++; }else if(0== vectextag[kedges[i].v1] && 0!=vectextag[kedges[i].v2]){ //v2顶点已经在最小生成树中 vectextag[kedges[i].v1]=vectextag[kedges[i].v2];//v2顶点所在树标志赋予v1顶点。 }else if(0!= vectextag[kedges[i].v1] && 0==vectextag[kedges[i].v2]){ vectextag[kedges[i].v2]=vectextag[kedges[i].v1];//v1顶点所在树标志赋予v2顶点。 }else{ //没有新节点,当2个顶点标志相同时说明它们已经在同一颗树 if(vectextag[kedges[i].v1] == vectextag[kedges[i].v2]) continue; //不同的小生成树,修改为同一棵生成树 for(j=0;j<n;j++){ if(vectextag[j] == vectextag[kedges[i].v1]){ //把等于v1的修改为顶点v2的点 vectextag[j]=vectextag[kedges[i].v2]; } }//end for }//end if //***访问边***// printf("v%c-v%c\n",G.vexs[kedges[i].v1],G.vexs[kedges[i].v2]); }//end for 遍历边 }/*******Dijkstra求最短路径目标:求指定起点到其他各顶点的最短路径和权重。基本思路:1.求指定点到其他顶点的权重。2.把各个点分别加入到其中时,比较权重之和。3.若小于原先的顶点,则替换新值********/void Dijkstra(MGraph G,int v0,int n){ int Distance[MaxVertexNum];//指定点到各顶点的权重。 int Path[MaxVertexNum]={-1};//Path的数值是由近到远。 int S[MaxVertexNum];//1表示顶点Source已经在源中了,0表示没有。 int v,i,min,j; //1.初始化权重、路径和是否在源中 for(v=0;v<n;v++){ S[v]=0;//是否在源中 Distance[v]=G.arcs[v0][v];//权重 if(Distance[v]<INT_MAX){ //有边 Path[v]=v0;//父节点为v0 } } Distance[v0]=0;//源点到自身的距离为0 S[v0]=1;//把v0点加入到源点中 //2.生成最短路径树 for(i=1;i<n;i++){//i=1是应为v0已经在源点的集合中,剩余n-1条边 min=INT_MAX;//最小的权重 for(j=0;j<n;j++){ if(!S[j] && Distance[j]<min){ v=j;//v0到其他顶点的最小权重 min=Distance[j]; } } S[v]=1;//把该顶点的最小权重边添加到源中 //更新权重表和路径 for(j=0;j<n;j++){ if( !S[j] && !(Distance[v]==INT_MAX || G.arcs[v][j]==INT_MAX) && //左边不能有INT_MAX,如果有会上溢 (Distance[v]+G.arcs[v][j]<Distance[j])){//走新节点v比原来的小 Distance[j]=Distance[v]+G.arcs[v][j];//更改为更小的路线 Path[j]=v;//j的父节点变成v } }//end for }//end for //3.访问路径 for(i=0;i<n;i++){ printf("v%c-(%d)-v%c\n",G.vexs[v0],Distance[i],G.vexs[i]);//显示v0到 }}int main(){ void PrimTest(); void DijkstraTest(); PrimTest(); DijkstraTest(); return 0;}void PrimTest(){ MGraph G1={ {'1','2','3','4','5','6'},//顶点 {//矩阵 {INT_MAX,6,1,5,INT_MAX,INT_MAX},//1到其他各个顶点 {6,INT_MAX,5,INT_MAX,3,INT_MAX},//2到其他各个顶点 {1,5,INT_MAX,5,6,4},//3到其他各个顶点 {5,INT_MAX,5,INT_MAX,INT_MAX,2}, {INT_MAX,3,6,INT_MAX,INT_MAX,6}, {INT_MAX,INT_MAX,4,2,6,INT_MAX} } }; Prim(G1,'1',6); printf("\n\n"); Kruskal(G1,6); printf("\n\n"); }void DijkstraTest(){ MGraph G2={ {'1','2','3','4','5','6'},//顶点 {//矩阵 // 1 2 3 4 5 6 {INT_MAX, 3 ,INT_MAX, 20 ,INT_MAX,INT_MAX},//1到其他各个顶点 {INT_MAX,INT_MAX, 2 ,INT_MAX, 4 ,INT_MAX},//2到其他各个顶点 {INT_MAX,INT_MAX,INT_MAX, 7 , 1 , 5 },//3到其他各个顶点 {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX}, {INT_MAX,INT_MAX, 3 ,INT_MAX,INT_MAX,INT_MAX} } }; Dijkstra(G2,0,6);}#endif
0 0
- 第6章 图的基本算法
- 算法导论代码 第22章 图的基本算法
- 算法导论 | 第22章基本的图算法
- 算法导论 第22章 图的基本算法 22.1 图的表示
- 算法导论 第22章 图的基本算法 22.1 图的表示
- 算法导论-第22章-基本的图算法-22.1 图的表示
- 算法导论 第22章 图的基本算法 22.4 拓扑排序
- 算法导论 第22章 图的基本算法 22.5 强联通分支
- 算法导论习题解-第22章基本的图算法
- 广度优先搜索(算法导论第22章-基本的图算法)
- 算法导论-第22章-基本的图算法-22.2 广度优先搜索(BFS)
- 算法导论-第22章-基本的图算法-22.3 深度优先搜索(DFS)
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- 算法导论 第22章 图的基本算法(一)
- 算法导论 第22章 图的基本算法(二) 深度优先搜索
- 算法导论 第22章 图的基本算法(三) 拓扑排序
- 算法导论 第22章 图的基本算法(四) 强连通分支
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- The Relation Between Gradient Descent and Cost Funtion(To be continued)
- 编译caffe
- 图解Linux命令之--fsck命令
- 获取其他进程的fs寄存器
- C++中最容易被人忘记的构造函数初始化列表
- 第6章 图的基本算法
- 你都付出了哪些努力
- HDU2026 首字母变大写
- Is it a Tree? 并查集 坑多
- POJ 3051 Satellite Photographs 可能会
- POJ1838 banana 并查集
- bzoj4730
- BZOJ2124 等差子序列
- 虚拟机设置固定IP地址,并且能访问外网