贪心算法设计实验报告Word格式.docx
- 文档编号:21079635
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:8
- 大小:19.03KB
贪心算法设计实验报告Word格式.docx
《贪心算法设计实验报告Word格式.docx》由会员分享,可在线阅读,更多相关《贪心算法设计实验报告Word格式.docx(8页珍藏版)》请在冰豆网上搜索。
C,选择第二条边C----E(修改上表)
对上表进行维护(任同上表,因为还没有两个集合合并)
D,选择第三条边(D-----F)(根据条件DF两点不再同一集合,改边可选)
然后就合并DF两点所在的集合D的前去是1,即A标记为0,E的标记也为0,合并因为61所以表修改如下
以后几步均如上判断两点是否在一个集合从而判断改边是否可取,并维护上表下面附上源代码
/**************************************************************************************************
Kruskal算法的实现
09网一殷赛***-*****13
输入:
图G(用结构体数组来存储每条边,包含每条边的节点)输出:
图G的最小生成树树
***************************************************************************************************/#includestdio.h#includestdlib.htypedefstructEdge{
chardot_1;
chardot_2;
intweight;
intleap;
}Edge;
Edge*selectionsort(Edge*array,intn)//选择排序(对边按权重由高到低排序){
inti,j,min,temp;
for(i=0;
ii++){
min=i;
for(j=i+1;
jj++)
if(array[min].weightarray[j].weight)
min=j;
if(min!
=i){
temp=array[i].weight;
}
Edge*Kruskal(Edge*Graph,intnum_e,int**V,intnum_v)//克鲁斯卡尔算法实现{
if(V[m]!
=V[n]m!
=V[n]n!
=V[m])//如果边的两个顶点不再一个集合则边是生成树的边(注意首节点的标记和集合里非首节点的标记不同)
array[min].weight=temp;
temp=array[i].dot_1;
array[i].dot_1=array[min].dot_1;
array[min].dot_1=temp;
temp=array[i].dot_2;
array[i].dot_2=array[min].dot_2;
array[min].dot_2=temp;
returnarray;
intm,n,test;
inti,j,t,k;
inum_e;
i++){
for(j=1;
jnum_v+1;
j++){}
if(Graph[i].dot_1==V[j])
m=j;
if(Graph[i].dot_2==V[j])
n=j;
Graph[i].leap=1;
if(V[n]==0){}else{}
//维护不相交集
k=1;
//对每个节点都检查是否为标记合格节点while(knum_v+1){
if(V[k]!
=0)//只要标记不为0都进行整理,只不过有些节点的标记整理前后是
if(V[m]==0){}else{}
if(V[m]V[n])else
V[V[n]]=V[m];
V[V[m]]=V[n];
if(mV[n])else
V[m]=V[n];
V[V[n]]=m;
if(nV[m])else
V[n]=V[m];
V[V[m]]=n;
一样的(即标记符合标准的节点)
if(V[m]==0V[n]==0)//如果边的两个顶点是两个集合的首节点则可以合并{
if(mn)else
V[n]=m;
V[m]=n;
{}k++;
t=V[k];
while(V[t]!
=0){}V[k]=t;
t=V[t];
//维护不相交集k=1;
while(knum_v+1){
=0){
}k++;
/*printf("
不相交集的情况:
\n"
);
for(test=1;
testnum_v+1;
test++)
printf("
%-4c"
V[test]);
%-4d"
*/
returnGraph;
voidmain(){inti,j,num_v,num_e,cost=0;
Edge*Graph=NULL;
int**V=NULL;
请输入土中有多少个顶点!
scanf("
%d"
num_v);
V=(int**)malloc(sizeof(int*)*2);
ii++)
V[i]=(int*)malloc(sizeof(int)*(num_v+1));
ii++)for(j=0;
j++)
V[i][j]=0;
for(i=1;
inum_v+1;
i++)
{}
请输入第%d个顶点:
"
i);
%c"
V[i]);
请输入图中有多少条边!
num_e);
Graph=(Edge*)malloc(sizeof(Edge)*num_e);
i++){}
Graph=selectionsort(Graph,num_e);
请输入第%d条边的权值和两个顶点!
i+1);
%d%c%c"
Graph[i].weight,Graph[i].dot_1,Graph[i].dot_2);
Graph[i].leap=0;
//以上部分是存储图
//--------------------------------------------------------------------------------------------------
Graph=Kruskal(Graph,num_e,V,num_v);
构成最小生成树的边和顶点分别是:
顶点1------------顶点2-------------边\n"
if(Graph[i].leap==1){
%c
%c-------------------------%d\n"
Graph[i].dot_1,Graph[i].dot_2,Graph[i].weight);
cost=cost+Graph[i].weight;
最小生成树的权值是:
%d\n"
cost);
2.用Prim算法实现最小生成树
假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树:
1:
初始化:
U={u0},TE={f}。
此步骤设立一个只有结点u0的结点集U和一个空的边集TE作为最小生成树的初始形态,在随后的算法执行中,这个形态会不断的发生变化,直到得到最小生成树为止。
2:
在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u0,v0),将此边加进集合TE中,并将此边的非U中顶点加入U中。
此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:
首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。
找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。
这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合,这一点在理解算法时要密切注意。
3:
如果U=V,则算法结束;
否则重复步骤2。
可以把本步骤看成循环终止条件。
我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边(图任如上图)
下面给出具体c语言代码和详解
该代码的存储结构是邻接矩阵上三角用来存储最小生成树的边,树边用-1标记,下三角用来存储原图,方便输出最小生成树上图的最后邻接矩阵如下:
(具体实现和解释见代码)(INF代表无穷,即不相邻)
/*********************************************************************************
09网一殷赛***-*****13Prim算法的实现
图G
输出:
图G的最小生成树
**********************************************************************************/#includestdio.h#includestdlib.h#defineINF*****
/*************************************************************************************
Prim算法最重要的部分在于从可以挑选的边中间挑选出最小值
并且对加入后会产生回路的边标记为不可选(此代码中将该边权值标记为INF即无穷大)每选中一条边就会加入一个点(就必须对与该点连接的边进行维护,即多产生回路边标记为无穷)找最小边则是从上三角中所有可选的行和列中选择选中的树边则标记为-1(其权值从下三角读出)
**************************************************************************************/
voidPrim(int**Graph,intnum_v)//转化为对上三角的维护{inti,j,leap=0,temp;
intm,n,min;
int*a=(int*)malloc(sizeof(int)*num_v);
inum_v;
a[i]=0;
a=1;
while(leap!
=num_v-1){min=INF;
i++)//搜索上三角中的最小值{if(a[i]==1){for(j=i+1;
jnum_v;
j++)//行中搜索{if(minGraph[i][j]Graph[i][j]0){min=Graph[i][j];
n=i;
temp=0;
for(j=0;
jj++)//列中搜索{if(minGraph[j][i]Graph[j][i]0){
min=Graph[j][i];
/*for(i=0;
i++)//检查矩阵中在那些行(列)可以选择最小值(即那些列和行是候选行和列)
a[i]);
temp=1;
if(temp==0)//为了区别出是在行还是在列中搜索到的元素else
Graph[m][n]=-1;
Graph[n][m]=-1;
ii++)//去掉行中回路边{}
for(i=m+1;
i++)//去掉列中回路边{}a[m]=1;
if(a[i]==1Graph[m][i]0){}
Graph[m][i]=INF;
if(a[i]==1Graph[i][m]0){}
Graph[i][m]=INF;
i++)//检验对上三角的维护,和下三角是否修改了(下三角保存了原树和用于输出最小生成树)}
voidmain(){
Graph=(int**)malloc(sizeof(int*)*num_v);
//动态生成二维数组用来存储图(邻接矩阵)for(i=0;
i++)//初始化矩阵
{}*/leap++;
%-4d\t"
Graph[i][j]);
inti,j;
intnum_v,num_e;
int**Graph=NULL;
char*V=NULL;
charch_1,ch_2;
intm,n;
请输入图的顶点数:
V=(char*)malloc(sizeof(char)*num_v);
Graph[i]=(int*)malloc(sizeof(int)*num_v);
Graph[i][j]=INF;
Graph[i][i]=0;
i++){printf("
请输入图的边数:
请输入第%d条边的顶点和权值:
%c%c%d"
ch_1,ch_2,weight);
j++){if(V[j]==ch_1)
if(V[j]==ch_2)
Graph[m][n]=weight;
Graph[n][m]=weight;
//以上是对图用邻接矩阵存储
//------------------------------------------------------------------------------------Prim(Graph,num_v);
最小生成树如下:
顶点----------------顶点-----------------权值\n"
weight=0;
if(Graph[i][j]==-1){}
%-2c----------------%-2c-----------------%-2d\n"
V[i],V[j],Graph[j][i]);
weight=weight+Graph[j][i];
最小生成树的权重是:
weight);
六、实验结果与分析
Kruskal算法适用于边稀疏的情形,而Prim算法适用于边稠密的情形
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 贪心 算法 设计 实验 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)