最小生成树matlab实现

合集下载

最小生成树,Prim算法实现

最小生成树,Prim算法实现

最⼩⽣成树,Prim算法实现最⼩⽣成树所谓最⼩⽣成树,就是⼀个图的极⼩连通⼦图,它包含原图的所有顶点,并且所有边的权值之和尽可能的⼩。

⾸先看看第⼀个例⼦,有下⾯这样⼀个带权图:它的最⼩⽣成树是什么样⼦呢?下图绿⾊加粗的边可以把所有顶点连接起来,⼜保证了边的权值之和最⼩:去掉那些多余的边,该图的最⼩⽣成树如下:下⾯我们再来看⼀个更加复杂的带权图:同样道理,下图绿⾊加粗的边可以把所有顶点连接起来,⼜保证了边的权值之和最⼩:去掉那些多余的边,该图的最⼩⽣成树如下:图的极⼩连通⼦图不需要回路,⽽是⼀个树形结构,所以⼈们才把它叫做最⼩⽣成【树】。

图的最⼩⽣成树也不是唯⼀的,同⼀个图可以有多个不同的最⼩⽣成树,但是他们的权值之和是⼀样的。

最⼩⽣成树的⽤处可多了,⽐如我们要在若⼲个城市之间铺设道路,⽽我们的预算⼜是有限的,那么我们就需要找出成本最低的⽅式铺路,最⼩⽣成树的作⽤就来了。

怎样铺设才能保证成本最低呢?城市之间的交通⽹就像⼀个连通图,我们并不需要在每两个城市之间都直接进⾏连接,只需要⼀个最⼩⽣成树,保证所有的城市都有铁路可以触达即可。

通常⽣成最⼩⽣成树常⽤的算法有两种,⼀种是 Kruskal 算法,另⼀种是 Prim 算法。

下⾯介绍下 Prim 算法Prim算法是如何⼯作的呢?这个算法是以图的顶点为基础,从⼀个初始顶点开始,寻找触达其他顶点权值最⼩的边,并把该顶点加⼊到已触达顶点的集合中。

当全部顶点都加⼊到集合时,算法的⼯作就完成了。

Prim算法的本质,是基于贪⼼算法。

接下来说⼀说最⼩⽣成树的存储⽅式。

我们最常见的树的存储⽅式,是链式存储,每⼀个节点包含若⼲孩⼦节点的指针,每⼀个孩⼦节点⼜包含更多孩⼦节点的指针:这样的存储结构很清晰,但是也相对⿇烦。

为了便于操作,我们的最⼩⽣成树⽤⼀维数组来表达,数组下标所对应的元素,代表该顶点在最⼩⽣成树当中的⽗亲节点。

(根节点没有⽗亲节点,所以元素值是-1)下⾯让我们来看⼀看算法的详细过程:1.选择初始顶点,加⼊到已触达顶点集合。

最小生成树问题的ampl实际案例

最小生成树问题的ampl实际案例

最小生成树问题的AMPL实际案例导言在图论中,最小生成树指的是在一个连接了所有节点的图中,找到一棵权重之和最小的树。

最小生成树问题被广泛应用于网络设计、电路布线、城市规划等领域。

AMPL(A Mathematical Programming Language)是一种用于数值分析和优化的高级建模语言。

本文将通过一个具体的案例,探讨如何使用AMPL解决最小生成树问题。

案例背景假设我们有一个城市网络,城市之间通过道路连接。

我们希望使用最小的成本来连接所有城市,以便人们可以在城市之间通行。

问题分析我们可以将城市网络表示为一个带权重的图,其中城市是节点,道路是边,道路的权重表示建造和维护道路的成本。

我们的目标是找到一个最小生成树,即在图中选择一些边,使得所有的城市都能够通过这些边连通,并且这些边的权重之和最小。

数学建模为了使用AMPL解决最小生成树问题,我们需要将问题建模成一个线性规划模型。

首先,我们定义一些变量: - x ij表示边(i,j)是否被选择,如果被选择则取值为1,否则取值为0。

- c ij表示边(i,j)的权重。

然后,我们需要定义一些约束条件: - 每个城市必须通过某条边连接到最小生成=1,其中j表示与城市i相连的边树中的其他城市。

对于每个城市i,我们有∑x ijj(i,j)。

- 最小生成树中不能形成环。

对于每个子集S,使得S中的城市通过(i,j)连≤|S|−1。

接到最小生成树中的其他城市,我们有∑x ij(i,j)⊆S最后,我们需要定义目标函数: - 目标函数是最小化边的权重之和。

我们有min∑c ijx ij。

i,jAMPL代码下面是用AMPL建模的代码:set Cities; # 定义城市集合param c{Cities, Cities} >= 0; # 定义边的权重矩阵var x{Cities, Cities} binary; # 是否选择边minimize Total_Cost: sum{i in Cities, j in Cities} c[i,j] * x[i,j];subject to Connectedness{i in Cities}:sum{j in Cities} x[i,j] = 1;subject to No_Cycles{S in subset(Cities)}:sum{(i,j) in (S cross S)} x[i,j] <= card(S) - 1;结果分析通过运行AMPL代码,我们可以得到最小生成树的解。

Primf及Krusf最小成树及matlab源代码

Primf及Krusf最小成树及matlab源代码

11
2013年8月21日11 Nhomakorabea
例 、一个乡有7个自然村,其间道路如图 所示,要以村为中心建有线广播网络,如 要求沿道路架设广播线,应如何架设?
a
18
19 14 16 12
b
7
8
5
c
3
e
f
g
27
21
d
12
数学建模-图论
四、最小生成树问题及其算法
Prim 算法 Matlab 程序如下:
function T =Primf(a) l=length(a); a(a==0)=inf; k=1:l; listV(k)=0; listV(1)=1; e=1; while(e<l) min=inf; for i=1:l if listV(i)==1 for j=1:l if listV(j)==0 & min>a(i,j) min=a(i,j); b=a(i,j); s=i; d=j; end end end end
10
数学建模-图论
四、最小生成树问题及其算法
求最小生成树的 Prim 算法的思想如下:
从连通图 G=<V,E>的某一顶点 v 出发,选择与其关联的具有最小权的边 (u0,v),将其顶点加入到生成树的顶点集合 U 中。以后每一步从一个顶点 在 U 中而另一顶点不在 U 中的各条边中选择权值最小的边(u,v) ,把它的 顶点加入到集合 U 中,如此下去,直到图中的所有顶点都加入到生成树顶点 集合 U 中为止,这时得到一颗最小生成树。
0 2 2 0 4 4 0 8 A 8 0 4 5 3 7 8 5 3 7 8 0 3 7 3 0 6 7 6 0 4

数学建模-最小生成树-kruskal算法及各种代码

数学建模-最小生成树-kruskal算法及各种代码

kruskal算法及代码---含伪代码、c代码、matlab、pascal等代码K r u s k a l算法每次选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。

注意到所选取的边若产生环路则不可能形成一棵生成树。

K r u s k a l算法分e 步,其中e 是网络中边的数目。

按耗费递增的顺序来考虑这e 条边,每次考虑一条边。

当考虑某条边时,若将其加入到已选边的集合中会出现环路,则将其抛弃,否则,将它选入。

目录Kruskal算法Kruskal算法的代码实现Kruskal算法Kruskal算法的代码实现算法定义克鲁斯卡尔算法假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。

之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。

依次类推,直至森林中只有一棵树,也即子图中含有n-1条边为止。

举例描述克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个。

这里面充分体现了贪心算法的精髓。

大致的流程可以用一个图来表示。

这里的图的选择借用了Wikipedia上的那个。

非常清晰且直观。

首先第一步,我们有一张图,有若干点和边如下图所示:第一步我们要做的事情就是将所有的边的长度排序,用排序的结果作为我们选择边的依据。

这里再次体现了贪心算法的思想。

资源排序,对局部最优的资源进行选择。

排序完成后,我们率先选择了边AD。

这样我们的图就变成了第二步,在剩下的变中寻找。

数据结构最小生成树

数据结构最小生成树

p= new CSNode(v);
if(first){
V
T.lchild=p;first=false;
}
else{ q.nextsibling=p;} w1
w2
w3
q=p;
DFSTree(G,w.q); }
SG1
SG2
SG3
}
生成森林
一、定义 非连通图G的每个连通分量的生成树,
构成了图G的生成森林
生成森林
非连通图G:
0
1
a
b
2 3 45
cd
ef
7h
k8
G的深度优先搜索生 成森林:
ab
6 g
cg
h
df
k e
生成森林算法
void DFSForest(Graph G, CSNode T){ T=null; for(v=0;v=G.vexnum;++v)
v.visit=false; for(v=0;v=G.vexnum;++v)
4
13
10
v1
2
v2
1
v3
2
v4
7
v5
v3
2
v4
v5
58
4

1
v7
Kruskal算法
算法描述:
构造非连通图 ST=(V,{ }); k=i=0; // k 选中的边数 while (k<n-1) { ++i; 检查边集E中第i条权值最小的边(u,v); if 若(u,v)加入ST后不使ST中产生回路, 则输出边(u,v); 且k++;
生成树算法
void DFSTree(Graph G,int v,CSNode T){ 算法以孩子

最小生成树算法代码

最小生成树算法代码

最小生成树算法代码最小生成树算法是一种用于解决图论问题的算法,它的主要目的是在给定的图中找到一棵包含所有节点的树,并且这棵树的边权值之和最小。

最小生成树算法有多种实现方式,其中最常用的是Prim算法和Kruskal算法。

Prim算法是一种贪心算法,它从一个起始节点开始,每次选择与当前已经构建的树相邻的最小边,将其加入到树中。

具体实现过程如下:1. 选择一个起始节点,将其加入到已构建的树中。

2. 从与已构建的树相邻的边中选择一条权值最小的边,将其加入到树中。

3. 重复第二步,直到所有节点都被加入到树中。

Kruskal算法是一种基于并查集的贪心算法,它将所有边按照权值从小到大排序,然后依次加入到树中,如果加入某条边会形成环,则不加入该边。

具体实现过程如下:1. 将所有边按照权值从小到大排序。

2. 依次选择每条边,如果加入该边不会形成环,则将其加入到树中。

3. 重复第二步,直到所有节点都被加入到树中。

下面是Prim算法和Kruskal算法的代码实现:Prim算法:```#include <iostream>#include <vector>#include <queue>#include <cstring>using namespace std;const int INF = 0x3f3f3f3f;struct Edge {int to, weight;Edge(int t, int w) : to(t), weight(w) {}};vector<Edge> graph[1000];int dist[1000];bool visited[1000];void prim(int start) {memset(dist, INF, sizeof(dist));memset(visited, false, sizeof(visited));dist[start] = 0;priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;pq.push(make_pair(0, start));while (!pq.empty()) {int u = pq.top().second;pq.pop();if (visited[u]) continue;visited[u] = true;for (int i = 0; i < graph[u].size(); i++) {int v = graph[u][i].to;int w = graph[u][i].weight;if (!visited[v] && w < dist[v]) {dist[v] = w;pq.push(make_pair(dist[v], v));}}}}```Kruskal算法:```#include <iostream>#include <vector>#include <algorithm>using namespace std;struct Edge {int from, to, weight;Edge(int f, int t, int w) : from(f), to(t), weight(w) {} bool operator<(const Edge& other) const {return weight < other.weight;}};vector<Edge> edges;int parent[1000];int find(int x) {if (parent[x] == x) return x;return parent[x] = find(parent[x]); }void kruskal() {sort(edges.begin(), edges.end()); for (int i = 0; i < 1000; i++) {parent[i] = i;}for (int i = 0; i < edges.size(); i++) { int u = edges[i].from;int v = edges[i].to;int w = edges[i].weight;int pu = find(u);int pv = find(v);if (pu != pv) {parent[pu] = pv;// add edge to MST}}}以上是Prim算法和Kruskal算法的代码实现,它们都可以用于求解最小生成树问题。

Kruskal算法寻找最小树的matlab程序

Kruskal算法寻找最小树的matlab程序

Kruskal算法寻找最小树的matlab程序function tree=kruskal(d) %矩阵d为无向图的权矩阵,且是对称矩阵N=size(d,1);k=0; %记录图中边的条数I=max(max(d)); %I作为无穷大edge=zeros(N*(N-1)/2,3);%用于存储图中所有的边,边的条数最多为n*(n-1)/2for i=1:N-1 %因为权矩阵是对称阵,所以只用上三角矩阵。

for j=i+1:Nif d(i,j)<Ik=k+1;edge(k,1)=i;edge(k,2)=j;edge(k,3)=d(i,j);endendendedge=edge(1:k,:); %删除多余的行。

o_edge=edge; %用于存储排序后的边及边的端点。

for i=1:k-1 %用选择排序法进行升序排序for j=i+1:kif o_edge(i,3)>o_edge(j,3)temp=o_edge(i,:);o_edge(i,:)=o_edge(j,:);o_edge(j,:)=temp;endendendtree=zeros(N-1,3); %用于存放最小树中的边及边的端点,最小树中的边数为节点数减1 tree(1:2,:)=o_edge(1:2,:); %两条边一定不能构成圈,所以前面最小的两条边一定在最小树中。

line=3;for i=3:kif line==N %如果line=N说明tree矩阵已填满,最小树已经找到,跳出循环break;elseif line<Nif isempty(find(tree(:,1:2)==o_edge(i,1), 1))||isempty(find(tree(:,1:2)==o_edge(i,2), 1))%判断tree中已经确定的的所有边中的节点是否和新增加的边的两个端点都重复,若新边的两个端点不都重复,则为真%直接说明新边符合条件,加入tree中。

Matlab实现生成树计数

Matlab实现生成树计数

Matlab 实现生成树计数摘要在信息学竞赛中,有关生成树的最优化问题如最小生成树等是我们经常遇到的,而对生成树的计数及其相关问题则少有涉及。

事实上,生成树的计数是十分有意义的,在许多方面都有着广泛的应用。

本文首先介绍了行列式的基本概念、性质,并在此基础上引入Matrix Tree -定理。

关键字:生成树的计数、Matrix Tree -定理Matrix Tree -定理(Kirchhoff 矩阵-树定理)。

Matrix Tree -定理是解决生成树计数问题最有力的武器之一。

它首先于1847年被Kirchhoff 证明。

在介绍定理之前,我们首先明确几个概念:1、G 的度数矩阵[]D G 是一个n 阶矩阵,并且满足:0;().ij G i i j d d v i j =⎧=⎨≠⎩ ,()G i d v 为顶点i v 的度数(度数即与顶点i v 关联的边的个数)。

2、G 的邻接矩阵[]A G 也是一个n 阶矩阵, 并且满足:01i j ij i j v v a v v ⎧=⎨⎩;;没直接连接直接连接 我们定义G 的Kirchhoff 矩阵(也称为拉普拉斯算子)[]C G 为[][][]C G D G A G =-,则Matrix Tree -定理可以描述为:G 的所有不同的生成树的个数等于其Kirchhoff 矩阵[]C G 任何一个1n -阶主子式的行列式的绝对值。

所谓1n -阶主子式,就是对于()1r r n ≤≤,将[]C G 的第r 行、第r 列同时去掉后得到的新矩阵,用[]Cr G 表示。

Matlab 程序:function n=STREEC( D,A )C=D-A;,n=size(C);C(:,n)=[]; %删除矩阵C 的第n 列C(n,:)=[]; %删除矩阵C 的第n 行,形成了Cr ,为了节约空间,这里没有定义新的变量Cr,用C 代替Crn=abs(det(C)); %这里C 表示Cr.end。

反圈法(最小支撑树)

反圈法(最小支撑树)
End
五、调试过程
1.程序代码
function tr=mintree(a) n=length(a); flag=1; k=n-1; e(1)=1; e(2:n)=0; for s=1:k k=k-1; min=inf; for j=1:n for i=1:n if(e(i)==1&e(j)==0&min>a(i,j)&a(i,j)~=0) col=j; row=i;
3 v2 4
4 v3 3
1 v5
v7 总权重 w(T ) 为 17。
对于没有最小支撑树的情况,可以将(d)问题中的 v1v4 , v4 v5 , v3v4 , v5v6 ,对应的边 抹去,易知其不存在最小支撑树。代入数据,运行程序如下。 输入:
4
云南大学数学与统计学院实验教学中心
b=[0 3 6 0 0 0 0;3 0 4 0 0 0 7;6 4 0 0 5 0 3;0 0 0 0 0 2 0; 0 0 5 0 0 0 6;0 0 0 2 0 0 0;0 7 3 0 6 0 0]; tr=mintree(b); 输出: 没有最小支撑树 因为将 v4 , v6 独立出来,所以图 G 并不连通,故不能得到最小支撑树。
2.运行窗口
输入: a=[0 3 1 1 0 0 0;3 0 2 0 0 5 0;1 2 0 0 2 0 0;2 0 0 0 2 0 3; 0 0 2 2 0 3 2;0 5 0 0 3 0 4;0 0 0 3 2 4 0]; tr=mintree(a); 输出: tr = 0 0 1 1 0 0 0 0 0 2 0 0 0 0 1 2 0 0 2 0 0 2 0 0 0 0 0 0 0 0 2 0 0 3 2 0 0 0 0 3 0 0 0 0 0 0 2 0 0

最小生成树matlab实现

最小生成树matlab实现

primclear all;close all;Graph1;%调用Graph1M文件,产生图1的邻接矩阵%Graph2;%调用Graph2M文件,产生图2的邻接矩阵len=length(graph_adjacent);%求图中有多少个顶点k=sprintf('please input the point where you want to start ,do rem ember it must be between 1 and %d ',len);start_point=input(k);%输入最小生成树产生起点while((start_point<=0)|(start_point>len))%如果输入的结点位置不合法即:小于等于零,或大于结点数,则重新输入disp('bad positon,please input again!');start_point=input(k);end;%************************************下面完成prim算法************** **************%相关变量初始设置tree=zeros(len-1,2);%用于保存选入最小生成树的边lowcost=zeros(1,len);%用来保存集合V-U与集合U中顶点的最短边权值,lowcost [v]=0表示顶点v已经%加入最小生成树中adjvex=zeros(1,len);%用来保存依附于该边在集合U中的节点,U集合为生成最小生成树的辅助集合,%首先U={start_point},之后依次确定为把最小生成树的一边的另一节点加入U%依次下去,直到图的全部顶点都在U中能找到lowcost=graph_adjacent(start_point,:);%lowcost(i)的值为节点i与start _point的权值;adjvex=start_point.*ones(1,len);%adjvex中所有元素的值都为初始节点%以下循n-1次,用于找出最小生成树的len-1条边for i=1:len-1k=lowcost>0;%k为一逻辑数组,它和lowcost同维,对于每一个位置i1lowcos t(i)>0则k(i)=1%否则k(i)=0;稍候将用这个数组进行辅助寻址cost_min=min(lowcost(k));%找出lowcost中除0外的最小值index=find(lowcost==cost_min);%找出此最小值在lowcost中的下标,即找到相应的节点index=index(1);%因为最小值的下标可能不止一个,这里取第一个下标进行处理 lowcost(index)=0;%表明该节点已经加入了最小生成树中tree(i,:)=[adjvex(index),index];%对lowcost和adjvex进行更新for j=1:lenif lowcost(j)>graph_adjacent(j,index);lowcost(j)=graph_adjacent(j,index);adjvex(j)=index;endendend;%*************************结果显示模块***************************** *******s=0;for ii=1:len-1k=sprintf('最小生成树第%d条边:(%d,%d),权值为%d',ii,tree(ii,1),tr ee(ii,2),graph_adjacent(tree(ii,1),tree(ii,2)));%格式化字符串%disp(k);%显示%disp(' ');%空一行s=s+graph_adjacent(tree(ii,1),tree(ii,2)); %求最小生成树的代价end%显示最小生成树的代价disp('最小生成树的总代价为:')disp(s);kruskalclear all;close all;Graph11;%调用以邻接矩阵储存的图所在的M文件%Graph22;len=length(graph_adjacent);%计算图中的顶点数temp=graph_adjacent;%将原图内容拷贝到temp中,以防对原图做改动superedge=zeros(len-1,2);%用于保存生成最小生成树的边i=1;%指向superedge的下标for j=1:lentag(j)=j;%关联标志初始化,将每个顶点的关联标志设为其本身end;%以下的循环完成kruskal算法while(superedge(len-1,1)==0)[Y,I]=sort(temp);%将temp的每列按从小到大排序,数组Y保存temp 排序后的结果,I中保存相应结果对应的在temp中的下标cost_min=min(Y(1,:));%找出权值最小的边index=find(Y(1,:)==cost_min);%找出权值最小的边对应的顶点index=index(1);%一条边对应两个节点,且不同的边的权值可能一样,这里为了方便处理人为规定了顺序,取标号最小的顶点进行处理anotherpoint=I(1,index);%找到该边对应的另一个顶点%将该边对应的权值修改为最大,防止该边在下次循环中再次被选为最优边temp(index,anotherpoint)=100;temp(anotherpoint,index)=100;if(tag(anotherpoint)~=tag(index))%当两个点不属于一个连通集时,这两个点之间的边为最小生成树的边superedge(i,:)=[index,anotherpoint];%将其加入最小生成树的边集中i=i+1;%下标加1%下面的语句的作用是将两个连通分支变成一个连通分支,即tag值一样for j=1:len%以index的tag值为标准if((tag(j)==tag(anotherpoint))&(j~=anotherpoint))%遍搜tag数组,先将和anotherpoint tag值一样的点的tag值变为index的tag值tag(j)=tag(index);endendtag(anotherpoint)=tag(index);%将anotherpoint的tag值变为in dex的tag值endend%*************************结果显示模块**************************** ********s=0;for ii=1:len-1k=sprintf('最小生成树第%d条边:(%d,%d),权值为%d',ii,superedge(ii,1),superedge(ii,2),graph_adjacent(superedge(ii,1),superedge(ii,2)));%格式化字符串%disp(k);%显示%disp(' ');%空一行s=s+graph_adjacent(superedge(ii,1),superedge(ii,2)); %求最小生成树的代价end%显示最小生成树的代价disp('最小生成树的总代价为:')disp(s);。

最小生成树matlab代码

最小生成树matlab代码

最小生成树matlab代码在Matlab中,最小生成树可以通过Kruskal算法和Prim算法来实现。

本文将分别介绍两种算法的代码实现,并对其进行详细解析。

Kruskal算法Kruskal算法是基于贪心算法的最小生成树算法。

其基本思想是将边按照权值从小到大进行排序,然后逐个加入到树中,直到树连通为止。

如果加入一条边使得形成环,则不加入该边。

定义一个函数Kruskal(weight,n)来实现Kruskal算法。

参数weight是一个n*n的矩阵,表示图的邻接矩阵;n表示图中节点的个数。

该函数的返回值为最小生成树的边集。

function edges=Kruskal(weight,n)%初始化[rows,cols,vals]=find(weight);edge_num=length(rows);%边数edges=zeros(n-1,2);%初始化,存放最小生成树的边%边按照权重从小到大排序[~,idx]=sort(vals);rows=rows(idx);cols=cols(idx);%初始化并查集par=1:n;rank=zeros(1,n);%依次加入边n_edge=0;%表示已加入的边数for i=1:edge_num%如果两个节点已经在同一连通块中,则不能加入当前边if FindPar(par,rows(i))==FindPar(par,cols(i))continue;end%将当前边加入到最小生成树中n_edge=n_edge+1;edges(n_edge,:)=[rows(i),cols(i)];%将两个节点合并Union(par,rank,rows(i),cols(i));%如果当前已经加入足够的边,则退出循环if n_edge==n-1break;endendFindPar函数和Union函数是实现并查集的两个函数,用于判断是否形成环以及将两个节点合并。

具体代码如下:%查找节点的祖先function par=FindPar(par,idx)if par(idx)==idxpar=idx;elsepar=FindPar(par,par(idx));end%将两个节点合并function Union(par,rank,x,y)x_par=FindPar(par,x);y_par=FindPar(par,y);if rank(x_par)>rank(y_par)par(y_par)=x_par;elsepar(x_par)=y_par;if rank(x_par)==rank(y_par)rank(y_par)=rank(y_par)+1;endendPrim算法Prim算法也是一种贪心算法,基本思想是从任意一个点开始,找到与该点相邻的最短边,然后将这个边连接的点加入到集合中,继续寻找与该集合相邻的最短边。

Matlab中避圈法求解最小生成树

Matlab中避圈法求解最小生成树
elseif P(2,l)==P(2,y) P(2,l)=P(1,y);
end
end
P(2,y)=P(1,y);
elseif P(2,y)<P(1,y)
for l=(y+1):m
%准备工作
T=zeros(n); %最小生成树的加权邻接矩阵
WW=W;
for i=1:n
for j=1:n
if W(i,j)==inf WW(i,j)=0;
end
end
end
m=((nnz(WW))/2); %图的边线的数目
%编程工具Matlab;程序名称MST_k.m.
%这是一个通过避圈法求解连通带权图的最小生成树的程序.
n=input('请输入图的顶点数目:n= ')
W=input('请输入图的加权邻接矩阵:[W(1,1),..,W(1,n);..;W(n,1),..,W(n,n)]=')
%用W(i,i)="inf" 代替 "=0"
end
W(a,b)=inf;
else %如果条件|E|=|V|-1成立
MST=T;
input('这个图的最小生成树的加权邻接矩阵是:')
MST
break
end
Байду номын сангаас
end
if j<(n-1) %如果条件|E|<|V|-1成立
input('这个图没有最小生成树.')
end
j=0; %最小生成树的边线的数目
%主要步骤
for i=1:m %被选择边线的数目

2023五一杯数学建模b题matlab代码

2023五一杯数学建模b题matlab代码

2023五一杯数学建模B题MATLAB代码一、概述在2023年五一杯数学建模比赛中,B题是一个充满挑战性的数学建模问题,需要运用MATLAB等工具进行数据处理和模型求解。

本文将针对该题目展开讨论,介绍相应的MATLAB代码。

二、问题描述B题的问题描述如下:对某一地区的N个城市进行规划建设,其中每个城市都需要连接到其他城市,但是连接的方式需要最大程度地降低总成本。

现有每个城市之间建设高速公路的成本数据,问题要求设计出一种最优的高速公路规划方案。

三、MATLAB代码展示1. 数据处理首先需要载入城市之间的成本数据,假设成本数据保存在一个名为cost_matrix的N*N矩阵中。

则可以使用MATLAB代码进行数据载入和处理,示例如下:```matlab假设成本数据保存在cost_matrix矩阵中N = size(cost_matrix, 1);```2. 模型求解需要设计一个数学模型来求解最优的高速公路规划方案。

这里可以采用最小生成树算法(Minimum Spanning Tree,MST)来解决问题。

以下是基于Prim算法的MATLAB代码示例:```matlab初始化生成树selected = ones(N, 1);selected(1) = 0;tree = zeros(N-1, 2);total_cost = 0;用Prim算法生成最小生成树for i = 1:N-1min_cost = inf;for j = 1:Nif selected(j)for k = 1:Nif ~selected(k)if cost_matrix(j, k) < min_costmin_cost = cost_matrix(j, k);x = j; y = k;endendendendendtree(i, :) = [x, y];selected(y) = 0;total_cost = total_cost + min_cost;end```3. 结果展示可以将生成的最小生成树结果进行可视化展示,以便于分析和进一步优化。

(图论)matlab模板程序

(图论)matlab模板程序

第一讲:图论模型程序一:可达矩阵算法%根据邻接矩阵A〔有向图〕求可达矩阵P〔有向图〕function P=dgraf<A>n=size<A,1>;P=A;for i=2:nP=P+A^i;endP<P~=0>=1; %将不为0的元素变为1P;程序二:无向图关联矩阵和邻接矩阵互换算法F表示所给出的图的相应矩阵W表示程序运行结束后的结果f=0表示把邻接矩阵转换为关联矩阵f=1表示把关联矩阵转换为邻接矩阵%无向图的关联矩阵和邻接矩阵的相互转换function W=incandadf<F,f>if f==0 %邻接矩阵转换为关联矩阵m=sum<sum<F>>/2; %计算图的边数n=size<F,1>;W=zeros<n,m>;k=1;for i=1:nfor j=i:nif F<i,j>~=0W<i,k>=1; %给边的始点赋值为1W<j,k>=1; %给边的终点赋值为1k=k+1;endendendelseif f==1 %关联矩阵转换为邻接矩阵m=size<F,2>;n=size<F,1>;W=zeros<n,n>;for i=1:ma=find<F<:,i>~=0>;W<a<1>,a<2>>=1; %存在边,则邻接矩阵的对应值为1 W<a<2>,a<1>>=1;endelsefprint<'Please imput the right value of f'>;W;程序三:有向图关联矩阵和邻接矩阵互换算法%有向图的关联矩阵和邻接矩阵的转换function W=mattransf<F,f>if f==0 %邻接矩阵转换为关联矩阵m=sum<sum<F>>;n=size<F,1>;W=zeros<n,m>;k=1;for i=1:nfor j=i:nif F<i,j>~=0 %由i发出的边,有向边的始点W<i,k>=1; %关联矩阵始点值为1W<j,k>=-1; %关联矩阵终点值为-1k=k+1;endendendelseif f==1 %关联矩阵转换为邻接矩阵m=size<F,2>;n=size<F,1>;W=zeros<n,n>;for i=1:ma=find<F<:,i>~=0>; %有向边的两个顶点if F<a<1>,i>==1W<a<1>,a<2>>=1; %有向边由a<1>指向a<2>elseW<a<2>,a<1>>=1; %有向边由a<2>指向a<1>endendelsefprint<'Please imput the right value of f'>;endW;第二讲:最短路问题程序0:最短距离矩阵W表示图的权值矩阵D表示图的最短距离矩阵%连通图中各项顶点间最短距离的计算function D=shortdf<W>%对于W<i,j>,若两顶点间存在弧,则为弧的权值,否则为inf;当i=j时W<i,j>=0 n=length<W>;m=1;while m<=nfor i=1:nfor j=1:nif D<i,j>>D<i,m>+D<m,j>D<i,j>+D<i,m>+D<m,j>; %距离进行更新 endendendm=m+1;endD;程序一:Dijkstra算法〔计算两点间的最短路〕function [l,z]=Dijkstra<W>n = size <W,1>;for i = 1 :nl<i>=W<1,i>;z<i>=0;endi=1;while i<=nfor j =1 :nif l<i>>l<j>+W<j,i>l<i>=l<j>+W<j,i>;z<i>=j-1;if j<ii=j-1;endendendi=i+1;end程序二:floyd算法〔计算任意两点间的最短距离〕function [d,r]=floyd<a>n=size<a,1>;d=a;for i=1:nfor j=1:nr<i,j>=j;endendr;for k=1:nfor i=1:nfor j=1:nif d<i,k>+d<k,j><d<i,j>d<i,j>=d<i,k>+d<k,j>; r<i,j>=r<i,k>;endendendend程序三:n2short.m 计算指定两点间的最短距离function [P u]=n2short<W,k1,k2>n=length<W>;U=W;m=1;while m<=nfor i=1:nfor j=1:nif U<i,j>>U<i,m>+U<m,j>U<i,j>=U<i,m>+U<m,j>;endendendm=m+1;endu=U<k1,k2>;P1=zeros<1,n>;k=1;P1<k>=k2;V=ones<1,n>*inf;kk=k2;while kk~=k1for i=1:nV<1,i>=U<k1,kk>-W<i,kk>;if V<1,i>==U<k1,i>P1<k+1>=i;kk=i;k=k+1;endendendk=1;wrow=find<P1~=0>;for j=length<wrow>:-1:1P<k>=P1<wrow<j>>;k=k+1;endP;程序四、n1short.m<计算某点到其它所有点的最短距离> function[Pm D]=n1short<W,k>n=size<W,1>;D=zeros<1,n>;for i=1:n[P d]=n2short<W,k,i>;Pm{i}=P;D<i>=d;end程序五:pass2short.m<计算经过某两点的最短距离> function [P d]=pass2short<W,k1,k2,t1,t2>[p1 d1]=n2short<W,k1,t1>;[p2 d2]=n2short<W,t1,t2>;[p3 d3]=n2short<W,t2,k2>;dt1=d1+d2+d3;[p4 d4]=n2short<W,k1,t2>;[p5 d5]=n2short<W,t2,t1>;[p6 d6]=n2short<W,t1,k2>;dt2=d4+d5+d6;if dt1<dt2d=dt1;P=[p1 p2<2:length<p2>> p3<2:length<p3>>]; elsed=dt1;p=[p4 p5<2:length<p5>> p6<2:length<p6>>]; endP;d;第三讲:最小生成树程序一:最小生成树的Kruskal算法function [T c]=krusf<d,flag>if nargin==1n=size<d,2>;m=sum<sum<d~=0>>/2;b=zeros<3,m>;k=1;for i=1:nfor j=<i+1>:nif d<i,j>~=0b<1,k>=i;b<2,k>=j;b<3,k>=d<i,j>;k=k+1;endendendelseb=d;endn=max<max<b<1:2,:>>>;m=size<b,2>;[B,i]=sortrows<b',3>;B=B';c=0;T=[];k=1;t=1:n;for i=1:mif t<B<1,i>>~=t<B<2,i>>T<1:2,k>=B<1:2,i>;c=c+B<3,i>;k=k+1;tmin=min<t<B<1,i>>,t<B<2,i>>>; tmax=max<t<B<1,i>>,t<B<2,i>>>; for j=1:nif t<j>==tmaxt<j>=tmin;endendendif k==nbreak;endendT;c;程序二:最小生成树的Prim算法function [T c]=Primf<a>l=length<a>;a<a==0>=inf;k=1:l;listV<k>=0;listV<1>=1;e=1;while <e<l>min=inf;for i=1:lif listV<i>==1for j=1:lif listV<j>==0 & min>a<i,j>min=a<i,j>;b=a<i,j>;s=i;d=j;endendendendlistV<d>=1;distance<e>=b;source<e>=s;destination<e>=d;e=e+1;endT=[source;destination];for g=1:e-1c<g>=a<T<1,g>,T<2,g>>;endc;第四讲:Euler图和Hamilton图程序一:Fleury算法〔在一个Euler图中找出Euler环游〕注:包括三个文件;fleuf1.m, edf.m, flecvexf.mfunction [T c]=fleuf1<d>%注:必须保证是Euler环游,否则输出T=0,c=0n=length<d>;b=d;b<b==inf>=0;b<b~=0>=1;m=0;a=sum<b>;eds=sum<a>/2;ed=zeros<2,eds>;vexs=zeros<1,eds+1>;matr=b;for i=1:nif mod<a<i>,2>==1m=m+1;endendif m~=0fprintf<'there is not exit Euler path.\n'>T=0;c=0;endif m==0vet=1;flag=0;t1=find<matr<vet,:>==1>;for ii=1:length<t1>ed<:,1>=[vet,t1<ii>];vexs<1,1>=vet;vexs<1,2>=t1<ii>;matr<vexs<1,2>,vexs<1,1>>=0;flagg=1;tem=1;while flagg[flagg ed]=edf<matr,eds,vexs,ed,tem>;tem=tem+1;if ed<1,eds>~=0 & ed<2,eds>~=0T=ed;T<2,eds>=1;c=0;for g=1:edsc=c+d<T<1,g>,T<2,g>>;endflagg=0;break;endendendendfunction[flag ed]=edf<matr,eds,vexs,ed,tem>flag=1;for i=2:eds[dvex f]=flecvexf<matr,i,vexs,eds,ed,tem>;if f==1flag=0;break;endif dvex~=0ed<:,i>=[vexs<1,i> dvex];vexs<1,i+1>=dvex;matr<vexs<1,i+1>,vexs<1,i>>=0;elsebreak;endendfunction [dvex f]=flecvexf<matr,i,vexs,eds,ed,temp> f=0;edd=find<matr<vexs<1,i>,:>==1>;dvex=0;dvex1=[];ded=[];if length<edd>==1dvex=edd;elsedd=1;dd1=0;kkk=0;for kk=1:length<edd>m1=find<vexs==edd<kk>>;if sum<m1>==0dvex1<dd>=edd<kk>;dd=dd+1;dd1=1;elsekkk=kkk+1;endendif kkk==length<edd>tem=vexs<1,i>*ones<1,kkk>;edd1=[tem;edd];for l1=1:kkklt=0;ddd=1;for l2=1:edsif edd1<1:2,l1>==ed<1:2,l2>lt=lt+1;endendif lt==0ded<ddd>=edd<l1>;ddd=ddd+1;endendendif temp<=length<dvex1>dvex=dvex1<temp>;elseif temp>length<dvex1> & temp<=length<ded>dvex=ded<temp>;elsef=1;endend程序二:Hamilton改良圈算法〔找出比较好的Hamilton路〕function [C d1]= hamiltonglf<v>%d表示权值矩阵%C表示算法最终找到的Hamilton圈.%v =[ 51 67;37 84;41 94;2 99;18 54;4 50;24 42;25 38;13 40;7 64;22 60;25 62;18 40;41 26];n=size<v,1>;subplot<1,2,1>hold on;plot <v<:,1>,v<:,2>,'*'>; %描点for i=1:nstr1='V';str2=num2str<i>;dot=[str1,str2];text<v<i,1>-1,v<i,2>-2,dot>; %给点命名endplot <v<:,1>,v<:,2>>;%连线plot<[v<n,1>,v<1,1>],[v<n,2>,v<1,2>]>;for i =1:nfor j=1:nd<i,j>=sqrt<<v<i,1>-v<j,1>>^2+<v<i,2>-v<j,2>>^2>;endendd2=0;for i=1:nif i<nd2=d2+d<i,i+1>;elsed2=d2+d<n,1>;endendtext<10,30,num2str<d2>>;n=size<d,2>;C=[linspace<1,n,n> 1];for nnn=1:20C1=C;if n>3for m=4:n+1for i=1:<m-3>for j=<i+2>:<m-1>if<d<C<i>,C<j>>+d<C<i+1>,C<j+1>><d<C<i>,C<i+1>>+d<C<j>,C<j+1>>>C1<1:i>=C<1:i>;for k=<i+1>:jC1<k>=C<j+i+1-k>;endC1<<j+1>:m>=C<<j+1>:m>;endendendendelseif n<=3if n<=2fprint<'It does not exist Hamilton circle.'>; elsefprint<'Any cirlce is the right answer.'>;endendC=C1;d1=0;for i=1:nd1=d1+d<C<i>,C<i+1>>;endd1;endsubplot<1,2,2>;hold on;plot <v<:,1>,v<:,2>,'*'>; %描点for i=1:nstr1='V';str2=num2str<i>;dot=[str1,str2];text<v<i,1>-1,v<i,2>-2,dot>; %给点命名endv2=[v;v<1,1>,v<1,2>];plot<v<C<:>,1>,v<C<:>,2>,'r'>;text<10,30,num2str<d1>>;第五讲:匹配问题与算法程序一:较大基础匹配算法function J=matgraf<W>n=size<W,1>;J=zeros<n,n>;while sum<sum<W>>~=0a=find<W~=0>;t1=mod<a<1>,n>;if t1==0t1=n;endif a<1>/n>floor<a<1>/n>t2=floor<a<1>/n>+1;elset2=floor<a<1>/n>;endJ<t1,t2>=1,J<t2,t1>=1;W<t1,:>=0;W<t2,:>=0;W<:,t1>=0;W<:,t2>=0;endJ;程序二:匈牙利算法〔完美匹配算法,包括三个文件fc01,fc02,fc03〕function [e,s]=fc01<a,flag>if nargin==1flag=0;endb=a;if flag==0cmax=max<max<b>'>;b=cmax-b;endm=size<b>;for i =1:m<1>b<i,:>=b<i,:>-min<b<i,:>>;endfor j=1:m<2>b<:,j>=b<:,j>-min<b<:,j>>;endd=<b==0>;[e,total]=fc02<d>;while total~=m<1>b=fc03<b,e>;d=<b==0>;[e,total]=fc02<d>;endinx=sub2ind<size<a>,e<:,1>,e<:,2>>;e=[e,a<inx>];s=sum<a<inx>>;function [e,total]=fc02<d>total=0;m=size<d>;e=zeros<m<1>,2>;t=sum<sum<d>'>;nump=sum<d'>;while t~=0[s,inp]=sort<nump>;inq=find<s>;ep=inp<inq<1>>;inp=find<d<ep,:>>;numq=sum<d<:,inp>>;[s,inq]=sort<numq>;eq=inp<inq<1>>;total=total+1;e<total,:>=[ep,eq];inp=find<d<:,eq>>;nump<inp>=nump<inp>-1;nump<ep>=0;t=t-sum<d<ep,:>>-sum<d<:,eq>>+1;d<ep,:>=0*d<ep,:>;d<:,eq>=0*d<:,eq>;endfunction b=fc03<b,e>m=size<b>;t=1;p=ones<m<1>,1>;q=zeros<m<1>,1>;inp=find<e<:,1>~=0>;p<e<inp,1>>=0;while t~=0tp=sum<p+q>;inp=find<p==1>;n=size<inp>;for i=1:n<1>inq=find<b<inp<i>,:>==0>;q<inq>=1;endinp=find<q==1>;n=size<inp>;for i=1:n<1>if all<e<:,2>-inp<i>>==0inq=find<<e<:,2>-inp<i>>==0>;p<e<inq>>=1;endendtq=sum<p+q>;t=tq-tp;endinp=find<p==1>;inq=find<q==0>;cmin=min<min<b<inp,inq>>'>;inq=find<q==1>;b<inp,:>=b<inp,:>-cmin;b<:,inq>=b<:,inq>+cmin;第六讲:最大流最小费用问题程序一:2F算法<Ford-Fulkerson算法>,求最大流%C=[0 5 4 3 0 0 0 0;0 0 0 0 5 3 0 0;0 0 0 0 0 3 2 0;0 0 0 0 0 0 2 0; %0 0 0 0 0 0 0 4;0 0 0 0 0 0 0 3;0 0 0 0 0 0 0 5;0 0 0 0 0 0 0 0 ] function [f wf]=fulkersonf<C,f1>%C表示容量%f1表示当前流量,默认为0%f表示最大流±íʾ×î´óÁ÷%wf表示最大流的流量n=length<C>;if nargin==1;f=zeros<n,n>;elsef=f1;endNo=zeros<1,n>;d=zeros<1,n>;while <1>No<1>=n+1;d<1>=Inf;while <1>pd=1;for <i=1:n>if <No<i>>for <j=1:n>if <No<j>==0 & f<i,j><C<i,j>>No<j>=i;d<j>=C<i,j>-f<i,j>;pd=0;if <d<j>>d<i>>d<j>=d<i>;endelseif <No<j>==0 & f<j,i>>0>No<j>=-i;d<j>=f<j,i>;pd=0;if <d<j>>d<i>>d<j>=d<i>;endendendendendif <No<n>|pd>break;endendif <pd>break;enddvt=d<n>;t=n;while <1>if<No<t>>0>f<No<t>,t>=f<No<t>,t>+dvt;elseif <No<t><0>f<No<t>,t>=f<No<t>,t>-dvt;endif <No<t>==1>for <i=1:n>No<i>=0;d<i>=0;endbreakendt=No<t>;endendwf=0;for <j=1:n>wf=wf+f<1,j>;endf;wf;程序二:Busacker-Gowan算法<求最大流最小费用>%C=[0 15 16 0 0;0 0 0 13 14;0 11 0 17 0;0 0 0 0 8;0 0 0 0 0] %b=[0 4 1 0 0;0 0 0 6 1;0 2 0 3 0;0 0 0 0 2;0 0 0 0 0]%function [f wf zwf]=BGf<C,b>%C表示弧容量矩阵%b表示弧上单位流量的费用%f表示最大流最小费用矩阵%wf最大流量%zwf表示最小费用n=size<C,2>;wf=0;wf0=inf;f=zeros<n,n>;while <1>a=ones<n,n>*inf;for <i=1:n>a<i,i>=0;endfor <i=1:n>for <j=1:n>if<C<i,j>>0 & f<i,j>==0>a<i,j>=b<i,j>;elseif <C<i,j>>0 & f<i,j>==C<i,j>>a<j,i>=-b<i,j>;elseif <C<i,j>>0>a<i,j>=b<i,j>;a<j,i>=-b<i,j>;endendendfor <i=2:n>p<i>=inf;s<i>=i;endfor <k=1:n>pd=1;for <i=2:n>for <j=1:n>if <p<i>>p<j>+a<j,i>>p<i>=p<j>+a<j,i>;s<i>=j;pd=0; endendendif <pd>break;endendif <p<n>==inf>break;enddvt=inf;t=n;while <1>if <a<s<t>,t>>0>dvtt=C<s<t>,t>-f<s<t>,t>;elseif <a<s<t>,t><0>dvtt=f<t,s<t>>;endif <dvt>dvtt>dvt=dvtt;endif <s<t>==1>break;endt=s<t>;endpd=0;if <wf+dvt>=wf0>dvt=wf0-wf;pd=1;endt=n;while <1>if <a<s<t>,t>>0>f<s<t>,t>=f<s<t>,t>+dvt; elseif <a<s<t>,t><0>f<<t>,s<t>>=f<t,s<t>>-dvt; endif <s<t>==1>break;endt=s<t>;endif <pd>break;endwf=0;for <j=1:n>wf=wf+f<1,j>;endendzwf=0;for <i=1:n>for <j=1:n>zwf=zwf+b<i,j>*f<i,j>;endendf;。

最小生成树和最短路径

最小生成树和最短路径

最小生成树和最短路径
最小生成树和最短路径都是图论中常见的概念,用于解决不同类型的图问题。

1. 最小生成树(Minimum Spanning Tree,MST):
最小生成树是指在一个连通加权无向图中找到一棵包含图中所有顶点的树,并且边的权重之和最小。

常用的算法有Prim算法和Kruskal算法。

- Prim算法:从一个初始顶点开始,逐步将与当前树集合相邻的具有最小权值的边加入,直至覆盖所有顶点为止。

- Kruskal算法:按边的权值从小到大的顺序考虑,逐步加入不构成回路的边,直到生成树中含有所有顶点为止。

2. 最短路径(Shortest Path):
最短路径是指在一个加权有向图或无向图中找到两个顶点之间权重和最小的路径。

常用的算法有Dijkstra算法和Bellman-Ford算法。

- Dijkstra算法:用于求解单个源点到图中所有其他顶点的最短路径,前提是图中不存在负权边。

- Bellman-Ford算法:可以处理存在负权边的情况,用于求解单个源点到图中所有其他顶点的最短路径。

这两个概念都涉及到图的遍历和路径查找,但目标和应用场景有所不同。

最小生成树着重于构建一个覆盖图所有顶点的树且总权值最小,而最短路径则是找到两点之间权重和最小的路径。

这些算法在网络规划、路径优化、通信网络等领域有着广泛的应用。

最小生成树(MATLAB)

最小生成树(MATLAB)

prim算法设置两个集合P和Q,其中P 用于存放G的最小生成树中的顶点,集合Q存放G的最小生成树中的边。

令集合P的初值为P={V1}(假设构造最小生成树时,从顶点V1出发),集合Q的初值为。

Prime算法的思想是,从所有p ∈P,v∈V-P的边中,选取具有最小权值的边pv,将顶点v加入集合P中,将边pv 加入集合Q中,如此不断重复,直到P=V时,最小生成树构造完毕,这时集合Q中包含了最小生成的所有边。

(找最小的权,不连成圈即可)•clc;clear;•M=1000;•a(1,2)=50; a(1,3)=60;•a(2,4)=65; a(2,5)=40;•a(3,4)=52;a(3,7)=45;•a(4,5)=50; a(4,6)=30;a(4,7)=42;•a(5,6)=70;•a=[a;zeros(2,7)];•a=a+a';a(find(a==0))=M;•result=[];p=1;tb=2:length(a);•while length(result)~=length(a)-1•temp=a(p,tb);temp=temp(:);•d=min(temp);•[jb,kb]=find(a(p,tb)==d);•j=p(jb(1));k=tb(kb(1));•result=[result,[j;k;d]];p=[p,k];tb(find(tb==k))=[];•end•result•例、一个乡有7个自然村,其间道路如图所示,要以村为中心建有线广播网络,如要求沿道路架设广播线,应如何架设?Kruskal算法每步从未选的边中选取边e,使它与已选边不构成圈,且e 是未选边中的最小权边,直到选够n-1条边为止。

•clc;clear;•M=1000;•a(1,2)=50; a(1,3)=60;•a(2,4)=65; a(2,5)=40;•a(3,4)=52;a(3,7)=45;•a(4,5)=50; a(4,6)=30;a(4,7)=42;•a(5,6)=70;•[i,j]=find((a~=0)&(a~=M));•b=a(find((a~=0)&(a~=M)));•data=[i';j';b'];index=data(1:2,:);•loop=max(size(a))-1;•result=[];•while length(result)<loop•temp=min(data(3,:));•flag=find(data(3,:)==temp);•flag=flag(1);•v1=data(1,flag);v2=data(2,flag);•if index(1,flag)~=index(2,flag)•result=[result,data(:,flag)];•end•if v1>v2•index(find(index==v1))=v2;•else•index(find(index==v2))=v1;•end•data(:,flag)=[];•index(:,flag)=[];•end•result中国邮递员问题中国邮递员问题也可以表示为:在一个有奇点的连通图中。

最小生成树的几个算法

最小生成树的几个算法

<图>最小生成树的几个算法。

一、Prim 算法:1、将图中顶点分为两个集合,其中集合X 包含图的一个顶点v0,集合Y 包含除v0 外的其它所有顶点;2、将跨接这两个集合的权值最小的边加入图中,并将其依附在集合Y 中的顶点v1 从Y 中移入集合X 中;3、反复过程2,直到集合Y 为空,所得生成子图即为最小生成树。

二、Kruskal 算法:1、将图中所有边按权值从小到大排序;2、取权值最小的边,加入图中,判断是否形成了回路,若无,则保留此边,否则去掉该边,重取权值较小的边;3、反复过程2,直到全部顶点均连通为止。

三、破圈法:1、在图中找到一个回路;2、去掉该回路中权值最大的边;3、反复此过程,直到图中不存在回路为止。

四、去边法:1、将图中所有边按权值从大到小排序;2、去掉权值最大的边,若图不再连通则保留此边,再选取下一权值较大的边去掉;3、反复此过程,直到图中只剩下n-1 条边为止。

下面的程序是实现Prim、去边法、Kruskal算法的。

弄好了久好久,出现了很多Bug,很多地方方法也可能不够简。

可能还有很多Bug,但先收手了。

第四次上机作业输入无向图的邻接矩阵,使用前面讲过的任意三种方法求该图的最小代价生成树,并分析各自的时间复杂度。

#include<iostream>#include<queue>using namespace std;/***************************基本上共用的大模块(结构定义,邻接矩阵输入)************************************/#define MAX_VERTEX_NUM 20typedef struct //存放连接矩阵权值的一个结点{int weight;}Adj,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];typedef struct //连接矩阵{AdjMatrix arc; //存权值的域int vexnum; //节点个数int edge; //边的个数}MGraph;typedef struct Node //用链表表示{int v1; //v1,v2为边的两个结点int v2;int weight;struct Node *next; //指向下一个结点}Node;typedef Node *NODEPTR;void CreateMGraph(MGraph &M){/*创建一个邻接矩阵表示有权图*/cout<<"请输入结点的个数:";cin>>M.vexnum;M.edge=0;cout<<"请输入该图的邻接矩阵:"<<endl; for(int i=1;i<=M.vexnum;i++){for(int j=1;j<=M.vexnum;j++){cin>>M.arc[i][j].weight;if(M.arc[i][j].weight)M.edge++;}}}/***********************查找最小生成树的Prim算法**********************************/struct Closedge{int adjvex;int lowcost;};struct Closedge closedge[MAX_VERTEX_NUM];//附设一个辅助数组,以记录从V-U具有最小代价的边。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

prim
clear all;
close all;
Graph1;%调用Graph1M文件,产生图1的邻接矩阵
%Graph2;%调用Graph2M文件,产生图2的邻接矩阵
len=length(graph_adjacent);%求图中有多少个顶点
k=sprintf('please input the point where you want to start ,do rem ember it must be between 1 and %d ',len);
start_point=input(k);%输入最小生成树产生起点
while((start_point<=0)|(start_point>len))%如果输入的结点位置不合法即:小于等于零,或大于结点数,则重新输入
disp('bad positon,please input again!');
start_point=input(k);
end;
%************************************下面完成prim算法************** **************
%相关变量初始设置
tree=zeros(len-1,2);%用于保存选入最小生成树的边
lowcost=zeros(1,len);%用来保存集合V-U与集合U中顶点的最短边权值,lowcost [v]=0表示顶点v已经
%加入最小生成树中
adjvex=zeros(1,len);%用来保存依附于该边在集合U中的节点,U集合为生成最小生成树的辅助集合,
%首先U={start_point},之后依次确定为把最小生成树的一边的另一节点加入U
%依次下去,直到图的全部顶点都在U中能找到
lowcost=graph_adjacent(start_point,:);%lowcost(i)的值为节点i与start _point的权值;
adjvex=start_point.*ones(1,len);%adjvex中所有元素的值都为初始节点
%以下循n-1次,用于找出最小生成树的len-1条边
for i=1:len-1
k=lowcost>0;%k为一逻辑数组,它和lowcost同维,对于每一个位置i1lowcos t(i)>0则k(i)=1
%否则k(i)=0;稍候将用这个数组进行辅助寻址
cost_min=min(lowcost(k));%找出lowcost中除0外的最小值
index=find(lowcost==cost_min);%找出此最小值在lowcost中的下标,即找到相应的节点
index=index(1);%因为最小值的下标可能不止一个,这里取第一个下标进行处理 lowcost(index)=0;%表明该节点已经加入了最小生成树中
tree(i,:)=[adjvex(index),index];
%对lowcost和adjvex进行更新
for j=1:len
if lowcost(j)>graph_adjacent(j,index);
lowcost(j)=graph_adjacent(j,index);
adjvex(j)=index;
end
end
end;
%*************************结果显示模块***************************** *******
s=0;
for ii=1:len-1
k=sprintf('最小生成树第%d条边:(%d,%d),权值为%d',ii,tree(ii,1),tr ee(ii,2),graph_adjacent(tree(ii,1),tree(ii,2)));%格式化字符串
%disp(k);%显示
%disp(' ');%空一行
s=s+graph_adjacent(tree(ii,1),tree(ii,2)); %求最小生成树的代价end
%显示最小生成树的代价
disp('最小生成树的总代价为:')
disp(s);
kruskal
clear all;
close all;
Graph11;%调用以邻接矩阵储存的图所在的M文件
%Graph22;
len=length(graph_adjacent);%计算图中的顶点数
temp=graph_adjacent;%将原图内容拷贝到temp中,以防对原图做改动
superedge=zeros(len-1,2);%用于保存生成最小生成树的边
i=1;%指向superedge的下标
for j=1:len
tag(j)=j;%关联标志初始化,将每个顶点的关联标志设为其本身
end;
%以下的循环完成kruskal算法
while(superedge(len-1,1)==0)
[Y,I]=sort(temp);%将temp的每列按从小到大排序,数组Y保存temp 排序后的结果,I中保存相应结果对应的在temp中的下标
cost_min=min(Y(1,:));%找出权值最小的边
index=find(Y(1,:)==cost_min);%找出权值最小的边对应的顶点
index=index(1);%一条边对应两个节点,且不同的边的权值可能一样,这里为了方便处理人为规定了顺序,取标号最小的顶点进行处理
anotherpoint=I(1,index);%找到该边对应的另一个顶点
%将该边对应的权值修改为最大,防止该边在下次循环中再次被选为最优边
temp(index,anotherpoint)=100;
temp(anotherpoint,index)=100;
if(tag(anotherpoint)~=tag(index))%当两个点不属于一个连通集时,这两个
点之间的边为最小生成树的边
superedge(i,:)=[index,anotherpoint];%将其加入最小生成树的边集中
i=i+1;%下标加1
%下面的语句的作用是将两个连通分支变成一个连通分支,即tag值一样for j=1:len%以index的tag值为标准
if((tag(j)==tag(anotherpoint))&(j~=anotherpoint))%遍搜tag数组,先将和anotherpoint tag值一样的点的tag值变为index的tag值
tag(j)=tag(index);
end
end
tag(anotherpoint)=tag(index);%将anotherpoint的tag值变为in dex的tag值
end
end
%*************************结果显示模块**************************** ********
s=0;
for ii=1:len-1
k=sprintf('最小生成树第%d条边:(%d,%d),权值为%d',ii,superedge(ii,
1),superedge(ii,2),graph_adjacent(superedge(ii,1),superedge(ii,
2)));%格式化字符串
%disp(k);%显示
%disp(' ');%空一行
s=s+graph_adjacent(superedge(ii,1),superedge(ii,2)); %求最小生成树的代价
end
%显示最小生成树的代价
disp('最小生成树的总代价为:')
disp(s);。

相关文档
最新文档