关于最小主树问题和最大公约数问题的C语言实现.docx

上传人:b****7 文档编号:9287499 上传时间:2023-02-04 格式:DOCX 页数:19 大小:231.73KB
下载 相关 举报
关于最小主树问题和最大公约数问题的C语言实现.docx_第1页
第1页 / 共19页
关于最小主树问题和最大公约数问题的C语言实现.docx_第2页
第2页 / 共19页
关于最小主树问题和最大公约数问题的C语言实现.docx_第3页
第3页 / 共19页
关于最小主树问题和最大公约数问题的C语言实现.docx_第4页
第4页 / 共19页
关于最小主树问题和最大公约数问题的C语言实现.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

关于最小主树问题和最大公约数问题的C语言实现.docx

《关于最小主树问题和最大公约数问题的C语言实现.docx》由会员分享,可在线阅读,更多相关《关于最小主树问题和最大公约数问题的C语言实现.docx(19页珍藏版)》请在冰豆网上搜索。

关于最小主树问题和最大公约数问题的C语言实现.docx

关于最小主树问题和最大公约数问题的C语言实现

 

重庆邮电大学研究生堂下考试答卷

 

2013-2014学年第一学期

考试科目算法分析与设计

姓名

学号

年级

专业

电话

 

2013年12月28日

目录

第1部分求最短主树问题………………………………1

1.1用P算法求解最短主树…………………………………1

1.1.1P算法求最短主树效率的理论分析………………1

1.1.2P算法求最短主树的C语言编程实现……………2

1.1.3P算法求最小主树问题的结果显示与分析……4

1.2用P算法求解最短主树……………………………………5

1.2.1P算法求最短主树效率的理论分析…………………5

1.2.2P算法求最短主树的C语言编程实现………………6

1.2.3P算法求最小主树的结果显示与分析……………7

1.3P算法和K算法的比较分析……………………………8

第2部分求最大公约数问题………………………………9

2.1用欧几里得算法求解最大公约数…………………………9

2.1.1欧几里得算法求最大公约数效率的理论分析………9

2.1.2欧几里得算法求最大公约数的C语言编程实现……9

2.1.3欧几里得算法求最大公约数的结果显示与分析…10

2.2用穷举算法求解最大公约数……………………………12

2.2.1穷举算法求最大公约数效率的理论分析…………12

2.2.2穷举算法求最大公约数的C语言编程实现………12

2.2.3穷举算法求最大公约数的结果显示与分析………13

2.3欧几里得算法和穷举法的比较分析……………………14

第3部分代码附录………………………………………16

第1部分:

求最短主树问题。

求最短主树问题是通信网理论课程和算法分析与设计课程的一个重要问题。

在任智老师和周应华老师的详细教学下,我对求最短主树问题有比较详细的了解。

因此,我选择了求最短主树作文本次考试的第一题。

对于求解此问题,比较常用的求解算法是P算法和K算法,这在通信网理论基础和算法分析与设计两门课程中都做了详细的介绍。

因此,对于此问题,我将选择P算法和K算法进行求解。

在求解最短主树问题前,我们有必要对最短主树概念有个一清晰的理解。

所谓最短主树,就是对于已知一个连接图端点数为n和各端间的距离dij,寻找一个边数为n-1的连接图,使其连接每一个端,同时使其权值和最小。

下面将以一个端数为6的图为例来分析其效率:

1.1P算法

1.1.1P算法求最短主树效率的理论分析:

算法的理论步骤:

(1)任取一端Vj1,,令端集合C1={Vj1},求出与其相邻的各端到它的距离,比较出最小距离端为Vj2,最小距离边为d(Vj1,,Vj2)。

则吧Vj2并入到C1中得到C2。

(2)再求C2中各个端到全端集除去C2的端的最短路径d(a,b),最短径端也就为b,将b并入C2得到C3。

(3)以此类推,直到Cn集合中包含所以的端集,各条最短径的连接图就是我们所求的最短径。

效率分析:

假设总共有n个端点,从算法开始到结束总共进行了n-1步。

每步必须从r个Cr的端与n-r个Cn-r个补端集的端进行比较,求出最小者。

可见,第r步中要做r(n-r)-1此比价。

所以算法的效率

N=(n-1)(n-2)(n+3)

这是数量级为n3的量级。

在上面给定的图中,由于给定了6个端,因此其效率N=(6-1)(6-2)(6+3)/6=20;

1.1.2P算法求最短主树的C语言编程实现:

对于prim算法的完整代码(基于上述给定连接图的算法)在附录1.1中完整给出。

现在将对其核心的代码进行具体的分析。

(1)、未来表示各个端的距离,此算法我定义了一二维数组dis[6][6]。

这里需要注意的是如果两个端点没有直接相连,他们的距离定义为无穷大。

这里,由于用数组无法表示无穷大,因此,定义了一个double型的值M,他的值为1000,代表两端无直接路径。

由于没有考虑自环,因此,本端到本端的距离也定义为1000。

(2)在prim算法中,最主要的问题就是寻找最短径的端的问题,因此在求解之前,定义了两个一位数组:

a[6]和b[6]。

在这里,前者适用于装载已找到最短距离的端点,后者适用于存放剩下的端点。

(3)、为了实现求最小主树。

本程序定义了一个集合Cr和它的补集端点之间的最短径函数prim(int*,int*,double(*)[6],int);

详细程序代码如下:

在此部分中,用到了一些技巧。

本函数返回一个整型变量值k,它的含义是在除了初始段外,已经找到了多少个断电了。

本连接图中,总共有6个端,在a[6]中,虽然初始全部为0,但是想表达的意思是已经存放了一个短端点V0。

所以是从V0开始查找。

返回一个整型变量k的目的是为了便于在a数组和b数组中交换位置。

例如,初始时候,a[6]={0,0,0,0,0,0},b[6]={1,2,3,4,5,0}这里b数组的最后一位为0,是因为在for循环中,最后一位不用,因为V0,已经在在a数组中,b数组的前五位代表五个端点的下标。

倘若在第一次循环中找到V0到V2路径最短,则上面的a数组将变为a[6]={0,2,0,0,0,0},b[6]={1,2,5,4,5,3}。

这里是是V2下标与后面V5下标交换,因为此时2这个端已经并到a集合,把2下标交换到后面相当于不用2下标了,因为由于返回值k的控制,for循环循环不到那个位置,相当于把2下标丢弃。

这正是程序最主要的思想。

1.1.3P算法求最短主树的结果显示与分析:

显示的结果所得最短主树为:

结果显示:

编程求解多的结果和理论分析的结果符合。

但是在代码执行的过程中,复杂度比之前的理论分析稍微复杂,这是因为理论分析只根据人脑直观的感觉来做出选择,而计算机只能蛮力进行一步步查找。

同时,由于存放端间距离使用的是数组,因此如果是预先没有定义端点的个数C程序在编译时候不能为数组分配空间,因此我选择了一个六个端的连接图来分析。

我觉得只要方法正确,使用范围就可以推而广之,广而推之,不失一般性。

1.2算法二:

K算法:

1.2.1K算法求最短主树效率的理论分析

Kruskal算法是指假设WN=(V,{E})是一个含有n个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:

先构造一个只含n个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有n棵树的一个森林。

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

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

这种算法的复杂性取决于把各边排成有序的队列。

当原理图中有n条边的时候,排序法有:

排序方法种类=n

这相当于做次比较。

对于m个端的图,它的最大边数为m*(m-1)/2,则它的复杂性为n2量级。

1.2.2K算法求最短主树的C语言实现:

完整代码在附录1.2。

与上边一样,本连接图总共只有10条边,因此,为了存放各端间的距离,我们一个10行3列的数组data[10][3],数组每一行存放的端点值,第三个数是存放这两个端点值的路径长度。

同时,为了便于查找和存放不同类型的值,我哟用到了结构体,其定义如下:

前面两个用于存放起点值和终点值,第三个定义了一个结构体指针用于后面查找。

这是一个求最小树的函数,这里需要注意的是if语句里面的条件,它非常重要,用于判断所加进去的边是否有环路,这是此算法的核心判别条件。

这是最小边查找函数。

1.2.3K算法求最小主树问题的结果显示与分析

实验结果显示如下:

所显示的最小主树如下:

由此,可知,实验结果与理论具有一致性。

在K算法中,主要涉及的就是变得排序和判断所加进去的边是否形成环这两个难点。

这也是需要注意的地方。

如何算法都必须具有普遍适用性,否则将失去意义。

1.3P算法和K算法的比较

P算法K算法在求解最小主树时候思想不一样。

前者主要是先考虑端在考虑变边,后者是先考虑边在考虑端。

这两种算法都比较简单易懂。

在算法效率上,K算法效率要比P算法高。

高的原因就是P算法需要循环地进行比较边的权值,后者主要是对边进行排序时开销比较大,但也不前者低。

 

第2部分:

求两个数的最大公约数

求解给定数的最大公约数问题也是算法分析里面看似一个经典问题。

倘若给的数太多,算法实现起来有一定的难度,用C语言实现起来也比较复杂繁琐。

因此,我将只研究两个数情形。

但是我想这不失一般性。

寻找结果问题的最重要的是找一个可行的搞笑的算法,因此,算法对于解决问题的重要性不言而喻。

2.1欧几里得算法(辗转相除法)

2.1.1辗转相除法求最大公约数问题的理论分析

辗转相除法是利用以下性质来确定两个正整数a和b的最大公因子的,其算法步骤如下:

1、若r是a÷b的余数,则

gcd(a,b)=gcd(b,r)2、a和其倍数之最大公因子为a。

另一种写法是:

1、a÷b,令r为所得余数(0≤r

2、互换:

置a←b,b←r,并返回第一步。

对于辗转相除法他没有的效率公式,它与输入规模决定。

这不仅仅是两个数大小的问题,而是看相除后余数的收敛速度。

2.1.2辗转相除法求最大公约数问题的c语言代码实现

这里,首先定义了需要输入的两个数a和b,这里需要的注意的是由于输入的两个数不管正负性如何都不影响其最大公约数,因此,为了便于计算,首先对其进行求绝对值,调用c语言math库里面的fabs函数进行就绝对值。

在进行其余运算时首先应判断两个数谁大谁小,同时为了进行值的交换,需要定义一个中间变量t。

为了进行不断的替换和取余,同时判断余数是否为零,这里用到了while循环。

2.1.3辗转相除法求最大公约数问题的结果显示与分析

当输入为99和11时,结果显示如下:

当输入为84和7时,其结果显示如下:

这是一个比较简单的问题,程序实现也是非常的简单,结果也正确。

用这个算法求最大公约数时使问题得到了极大的简化。

不愧以一种经典的求解方法。

2.2穷举法

2.2.1穷举法求最大公约数问题的理论分析

这是最简单的求解两个数最大公约是的方法。

这种算法思想比较简单,如下所述。

首先对输入的两个数进行比较,比较出其中较小的数因为两个数的最大公约数一定不大于这两个数中较小的那个数。

所以可以从最小数开始查找,及定义一个变量t作为除数。

如果这两个数不能同时被t整除,则t减1继续进行查找。

知道给出的两个数能同时被t整除。

这使得t值就是他们的最小最大公约数。

对于这种类似蛮力的做法,其算法的复杂度与输入的来那个个数关系比较大,也就说与输入规模有关。

同时,在一定程度上与两个数中最小的那个有关。

因为算法是从最小的那个数开始循环执行。

例如,若果给出的两个数a,和b互为质数,且a>b。

需要比较的次数就为b次。

再次,为了便于循环,先要对输入的的两个数进行取绝对值。

2.2.2穷举法求最大公约数问题的c语言代码实现

穷举法由于程序比较简单,所以其完整代码如下:

代码中定义了一个求最大公约数的函数divisor,这也是穷举法的核心语句。

这里需要注意的是当if语句里面的条件为假是,说明最大公约数已经找到。

这是需要对t进行减一,也就是执行t--代码。

此程序也调用了fabs函数用于取绝对值。

由于程序比较简单,这里不做过多的獒述。

2.2.3穷举法求最大公约数问题的结果显示与分析

结果显示如下:

上述结果与实际分析已知。

2.3欧几里得算法和穷举法的比较分析

虽然欧几里得算法和穷举法都能实现求最大公约数问题,单其算法的核心思想相差很大。

通过计算我们可以感觉到,欧几里得算法的平均复杂度远远定于穷举法。

当需要求解的数很小时,差别不是很大,但是当需要求解的两个数很大是欧几里得就显得比较高效。

但是,穷举法也有他的优点:

就是算法简单易懂。

条条大路通罗马,当我们是在想不出好方法时候,后者不失为一种方法。

 

第3部分附录代码

3.1P算法求最短主树的完整代码:

#include

intprim(int*,int*,double(*)[6],int);

voidmain()

{

doubleM=1000;

doubledis[6][6]={{M,6,1,5,M,M},{6,M,5,M,7,M},{1,5,M,7,5,4},{5,M,7,M,M,4},{M,3,5,M,M,6},{M,M,4,4,6,M}};

printf("各端点间的距离\n");

for(inti1=0;i1<6;i1++)

for(intj1=i1;j1<6;j1++)

{

if(dis[i1][j1]

printf("d(%d,%d)=(%f)\n",i1,j1,dis[i1][j1]);

}

intb[6]={1,2,3,4,5,0};

inta[6]={0,0,0,0,0,0};

printf("最短主树为:

\n");

intn=0;

for(inti=0;i<5;i++)

n=prim(a,b,dis,n);

}

intprim(int*a,int*b,double(*dis)[6],intk)

{

doubley=dis[a[0]][b[0]];

intx1,x2;

for(inti=0;i<=k;i++)

for(intj=0;j<5-k;j++)

{

if(dis[a[i]][b[j]]

{

y=dis[a[i]][b[j]];

x1=i;

x2=j;

}

}

if(y==dis[a[0]][b[0]])

{

x1=0;

x2=0;

}

printf("路径:

(%d,%d)径长:

d(%d%d)=%f;\n",a[x1],b[x2],a[x1],b[x2],y);

a[k+1]=b[x2];

b[x2]=b[4-k];

k=k+1;

returnk;

}

3.2K算法求最短主树的完整代码

#include

#defineVERTS6

structedge

{

intfrom,to;

intfind,val;

structedge*next;

};

typedefstructedgenode;

node*find_min_cost(node*);

voidmin_tree(node*);

intv[VERTS+1]={0};

voidmain()

{

intdata[10][3]={{0,1,6},{0,2,1},{0,3,5},{1,2,5},

{1,4,7},{2,3,7},{2,4,5},

{2,5,4},{3,5,4},{4,5,6}};

node*head,*ptr,*new_node;

head=NULL;

printf("各个端间的距离:

\n");

for(inti=0;i<10;i++)

{

for(intj=0;j

{

if(data[i][0]==j)

{

new_node=newnode;

new_node->from=data[i][0];

new_node->to=data[i][1];

new_node->val=data[i][2];

new_node->find=0;

new_node->next=NULL;

if(head==NULL)

{

head=new_node;

head->next=NULL;

ptr=head;

}

else

{

ptr->next=new_node;

ptr=ptr->next;

}

}

}

}

for(ptr=head;ptr!

=NULL;ptr=ptr->next)

printf("d(%d,%d)=%d\n",ptr->from,ptr->to,ptr->val);

printf("\n求得的最小主树:

\n");

min_tree(head);

putchar('\n');

}

voidmin_tree(node*head)

{

node*ptr,*tmptr;

intresult=0;

for(ptr=head;ptr!

=NULL;ptr=ptr->next)

{

tmptr=find_min_cost(head);

v[tmptr->from]++;

v[tmptr->to]++;

if(v[tmptr->from]>1&&v[tmptr->to]>1)

{

v[tmptr->from]--;

v[tmptr->to]--;

result=1;

}

elseresult=0;

if(result==0)

printf("路径:

(%d,%d)径长:

d(%d%d)=%d\n",tmptr->from,tmptr->to,tmptr->from,tmptr->to,tmptr->val);

}

}

node*find_min_cost(node*head)

{

intmin_val=100;

node*ptr,*tmptr;

for(ptr=head;ptr!

=NULL;ptr=ptr->next)

{

if(ptr->valfind==0)

{

min_val=ptr->val;

tmptr=ptr;

}

}

tmptr->find=1;

returntmptr;

}

注释:

第二个问题的两种求解算法的完整代码在前面已经完整给出,这里不再附录。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 商务科技

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1