zoukankan      html  css  js  c++  java
  • 有向图的强连通分量(最小生成树)

    // algo7-2.cpp 实现算法7.9的程序
    #include"c1.h"
    typedef int VRType;
    typedef char InfoType;
    #define MAX_NAME 3 // 顶点字符串的最大长度+1
    #define MAX_INFO 20 // 相关信息字符串的最大长度+1
    typedef char VertexType[MAX_NAME];
    #include"c7-1.h"
    #include"bo7-1.cpp"
    typedef struct
    { // 记录从顶点集U到V-U的代价最小的边的辅助数组定义(见图7.55)
    	VertexType adjvex;
    	VRType lowcost;
    }minside[MAX_VERTEX_NUM];
    int minimum(minside SZ,MGraph G)
    { // 求SZ.lowcost的最小正值,并返回其在SZ中的序号
    	int i=0,j,k,min;
    	while(!SZ[i].lowcost)
    		i++;
    	min=SZ[i].lowcost; // 第一个不为0的值
    	k=i;
    	for(j=i+1;j<G.vexnum;j++)
    		if(SZ[j].lowcost>0&&min>SZ[j].lowcost) // 找到新的大于0的最小值
    		{
    			min=SZ[j].lowcost;
    			k=j;
    		}
    		return k;
    }
    void MiniSpanTree_PRIM(MGraph G,VertexType u)
    { // 用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边。算法7.9
    	int i,j,k;
    	minside closedge;
    	k=LocateVex(G,u);
    	for(j=0;j<G.vexnum;++j) // 辅助数组初始化
    	{
    		strcpy(closedge[j].adjvex,u);
    		closedge[j].lowcost=G.arcs[k][j].adj;
    	}
    	closedge[k].lowcost=0; // 初始,U={u}
    	printf("最小代价生成树的各条边为
    ");
    	for(i=1;i<G.vexnum;++i)
    	{ // 选择其余G.vexnum-1个顶点
    		k=minimum(closedge,G); // 求出T的下一个结点:第k顶点
    		printf("(%s-%s)
    ",closedge[k].adjvex,G.vexs[k]); // 输出生成树的边
    		closedge[k].lowcost=0; // 第k顶点并入U集
    		for(j=0;j<G.vexnum;++j)
    			if(G.arcs[k][j].adj<closedge[j].lowcost)
    			{ // 新顶点并入U集后重新选择最小边
    				strcpy(closedge[j].adjvex,G.vexs[k]);
    				closedge[j].lowcost=G.arcs[k][j].adj;
    			}
    	}
    }
    void main()
    {
    	MGraph g;
    	CreateUDN(g); // 构造无向网g
    	Display(g); // 输出无向网g
    	MiniSpanTree_PRIM(g,g.vexs[0]); // 用普里姆算法从第1个顶点出发输出g的最小生成树的各条边
    }

    代码的运行结果 :

    请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): 6,10,0
    请输入6个顶点的值(<3个字符):
    V1 V2 V3 V4 V5 V6
    请输入10条边的顶点1 顶点2 权值(以空格作为间隔):
    V1 V2 6
    V1 V3 1
    V1 V4 5
    V2 V3 5
    V2 V5 3
    V3 V4 5
    V3 V5 6
    V3 V6 4
    V4 V6 2
    V5 V6 6
    6个顶点10条边或弧的无向网。顶点依次是: V1 V2 V3 V4 V5 V6 (见图756)

    G.arcs.adj:
    32767 6 1 5 32767 32767
    6 32767 5 32767 3 32767
    1 5 32767 5 6 4
    5 32767 5 32767 32767 2
    32767 3 6 32767 32767 6
    32767 32767 4 2 6 32767
    G.arcs.info:
    顶点1(弧尾) 顶点2(弧头) 该边或弧的信息:
    最小代价生成树的各条边为
    (V1-V3)
    (V3-V6)
    (V6-V4)
    (V3-V2)
    (V2-V5)


    图757 是根据以上程序运行的例子,显示了算法7.9(普里姆算法)求最小生成树的
    过程。首先,主程序构造了图756 所示的无向网。然后,调用MiniSpanTree_PRIM(),
    由顶点V1 开始,求该网的最小生成树。这样,最小生成树顶点集最初只有V1,其中用到
    了辅助数组closedge[]。closedge[i].lowcost 是最小生成树顶点集中的顶点到i 点的最小权
    值。若i 点属于最小生成树,则closedge[i].lowcost=0。closedge[i].adjvex 是最小生成树
    顶点集中到i 点为最小权值的那个顶点。图757(a)显示了closedge[]的初态。这时最小
    生成树顶点集中只有V1,所以closedge[i].adjvex 都是V1,closedge[i].lowcost 是V1 到i
    的权值。closedge[0].lowcost=0 , 说明V1 已属于最小生成树顶点集了。在
    closedge[].lowcost 中找最小正数,closedge[2].lowcost=1,是最小正数。令k=2,将V3
    并入最小生成树的顶点集(令closedge[2].lowcost=0),输出边(V1—V3)。因为V3 到
    V2、V5 和V6 的权值小于V1 到它们的权值,故将它们的closedge[].lowcost 替换为V3
    到它们的权值;将它们的closedge[].adjvex 替换为V3,如图757(b)所示。重复这个过
    程,依次如图757(c)、(d)和(e)所示。最后,closedge[]包含了最小生成树中每一条边
    的信息。


    // algo7-8.cpp 克鲁斯卡尔算法求无向连通网的最小生成树的程序
    #include"c1.h"
    typedef int VRType;
    typedef char InfoType;
    #define MAX_NAME 3 // 顶点字符串的最大长度+1
    #define MAX_INFO 20 // 相关信息字符串的最大长度+1
    typedef char VertexType[MAX_NAME];
    #include"c7-1.h"
    #include"bo7-1.cpp"
    void kruskal(MGraph G)
    {
    	int set[MAX_VERTEX_NUM],i,j;
    	int k=0,a=0,b=0,min=G.arcs[a][b].adj;
    	for(i=0;i<G.vexnum;i++)
    		set[i]=i; // 初态,各顶点分别属于各个集合
    	printf("最小代价生成树的各条边为
    ");
    	while(k<G.vexnum-1) // 最小生成树的边数小于顶点数-1
    	{ // 寻找最小权值的边
    		for(i=0;i<G.vexnum;++i)
    			for(j=i+1;j<G.vexnum;++j) // 无向网,只在上三角查找
    				if(G.arcs[i][j].adj<min)
    				{
    					min=G.arcs[i][j].adj; // 最小权值
    					a=i; // 边的一个顶点
    					b=j; // 边的另一个顶点
    				}
    				min=G.arcs[a][b].adj=INFINITY; // 删除上三角中该边,下次不再查找
    				if(set[a]!=set[b]) // 边的两顶点不属于同一集合
    				{
    					printf("%s-%s
    ",G.vexs[a],G.vexs[b]); // 输出该边
    					k++; // 边数+1
    					for(i=0;i<G.vexnum;i++)
    						if(set[i]==set[b]) // 将顶点b所在集合并入顶点a集合中
    							set[i]=set[a];
    				}
    	}
    }
    void main()
    {
    	MGraph g;
    	CreateUDN(g); // 构造无向网g
    	Display(g); // 输出无向网g
    	kruskal(g); // 用克鲁斯卡尔算法输出g的最小生成树的各条边
    }

    代码的运行结果:

    请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): 6,10,0
    请输入6个顶点的值(<3个字符):
    V1 V2 V3 V4 V5 V6
    请输入10条边的顶点1 顶点2 权值(以空格作为间隔):
    V1 V2 6
    V1 V3 1
    V1 V4 5
    V2 V3 5
    V2 V5 3
    V3 V4 5
    V3 V5 6
    V3 V6 4
    V4 V6 2
    V5 V6 6
    6个顶点10条边或弧的无向网。顶点依次是: V1 V2 V3 V4 V5 V6 (见图756)

    G.arcs.adj:
    32767 6 1 5 32767 32767
    6 32767 5 32767 3 32767
    1 5 32767 5 6 4
    5 32767 5 32767 32767 2
    32767 3 6 32767 32767 6
    32767 32767 4 2 6 32767
    G.arcs.info:
    顶点1(弧尾) 顶点2(弧头) 该边或弧的信息:
    最小代价生成树的各条边为
    (V1-V3)
    (V4-V6)
    (V2-V5)
    (V3-V6)
    (V2-V3)

    图758 是根据以上程序运行的例子,显示了克鲁斯卡尔算法求最小生成树的过程。
    首先,主程序构造了图756 所示的无向网。然后,调用kruskal(),求该网的最小生成
    树。其中用到了辅助数组set[]。set[i]表示第i 个顶点所在的集合。设初态set[i]=i,6 个
    顶点分属于6 个集合,如图758(a)所示。在邻接矩阵的上三角中找权值最小的边(因为
    是无向网),边(V1—V3)的权值最小,将V1 和V3 并到1 个集合中。方法是将V3 的集合
    set[2]赋值为set[0]( V1 的集合),同时将该边删除(令其上在三角的值为无穷)并输出该
    边,如图758(b)所示。用此方法依次将V4 和V6、V2 和V5 分别并到1 个集合中,如
    图758(c)、图758(d)所示。这时,邻接矩阵上三角中权值最小的边是(V3—V6),这
    两顶点分属于两个集合0 和3。将集合3 合并到集合0 中。方法是把集合3 中的V4、V6
    都并到集合0 中,如图758(e)所示。这时在邻接矩阵的上三角中首先找到的权值最小边
    是(V1—V4),但它们属于同一个集合(set[0]=set[3]=0),删除该边,继续查找。找到
    (V2—V3)是权值最小的边,且它们分属于不同的集合。把V3 所在集合中的顶点都并到
    V2 所在集合中,使所有顶点都在集合1 中,如图758(f)所示,最后构成了最小生成
    树。程序运行结果和普里姆算法的一样。


    需要指出的是,虽然在kruskal()中修改了无向网的邻接矩阵,由于kruskal()的形参不
    是引用类型,故在主调函数中并没有改变图的结构。

  • 相关阅读:
    P2660 zzc 种田
    ie发[e]的单词,ea发[e]的单词,e发i:的单词
    从员工表和部门表联合查询的不同方式看CBO对不同SQL的优化
    Delete..In.. 删除语句的优化再次探讨
    【Vue】第一个Vue例子
    再度思索:从配送表中选出订单号和配送者相同时的最新记录
    datx 编译打包命令
    kube-proxy iptables 模式源码分析
    kube-proxy ipvs 模式源码分析
    go json 反解析接口
  • 原文地址:https://www.cnblogs.com/KongkOngL/p/4074454.html
Copyright © 2011-2022 走看看