最小生成树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。

  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);。

相关文档
最新文档