经典算法C语言Word文件下载.docx

上传人:b****1 文档编号:1480464 上传时间:2023-04-30 格式:DOCX 页数:22 大小:42.82KB
下载 相关 举报
经典算法C语言Word文件下载.docx_第1页
第1页 / 共22页
经典算法C语言Word文件下载.docx_第2页
第2页 / 共22页
经典算法C语言Word文件下载.docx_第3页
第3页 / 共22页
经典算法C语言Word文件下载.docx_第4页
第4页 / 共22页
经典算法C语言Word文件下载.docx_第5页
第5页 / 共22页
经典算法C语言Word文件下载.docx_第6页
第6页 / 共22页
经典算法C语言Word文件下载.docx_第7页
第7页 / 共22页
经典算法C语言Word文件下载.docx_第8页
第8页 / 共22页
经典算法C语言Word文件下载.docx_第9页
第9页 / 共22页
经典算法C语言Word文件下载.docx_第10页
第10页 / 共22页
经典算法C语言Word文件下载.docx_第11页
第11页 / 共22页
经典算法C语言Word文件下载.docx_第12页
第12页 / 共22页
经典算法C语言Word文件下载.docx_第13页
第13页 / 共22页
经典算法C语言Word文件下载.docx_第14页
第14页 / 共22页
经典算法C语言Word文件下载.docx_第15页
第15页 / 共22页
经典算法C语言Word文件下载.docx_第16页
第16页 / 共22页
经典算法C语言Word文件下载.docx_第17页
第17页 / 共22页
经典算法C语言Word文件下载.docx_第18页
第18页 / 共22页
经典算法C语言Word文件下载.docx_第19页
第19页 / 共22页
经典算法C语言Word文件下载.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

经典算法C语言Word文件下载.docx

《经典算法C语言Word文件下载.docx》由会员分享,可在线阅读,更多相关《经典算法C语言Word文件下载.docx(22页珍藏版)》请在冰点文库上搜索。

经典算法C语言Word文件下载.docx

x0=3.1;

do{

  x0=2+4/x1+7/(x1*x1);

epsilon);

printf(“近似根是%.5f”,x1);

}

求的近似值为:

3.63199。

想一想 迭代公式采用x=(

-7)/4行吗?

不妨试一试。

  另外迭代算法也常用于求方程组的根,设方程组为:

xi=gi(X)(I=0,1,…,n-1)

令初始值为:

  X=(x0,x1,…,xn-1)  

  则求方程组近似根的迭代算法可描述如下:

  【算法】迭代法求方程组的根

  {for(i=0;

i<

=n-1;

i++)  x[i]=初始近似根;

  for(i=0;

i++)  y[i]=x[i];

i++)  x[i]=gi(X);

for(delta=0.0,i=0;

i++)

  if(fabs(y[i]-x[i])>

delta)

delta=fabs(y[i]-x[i]);

  }while(delta>

for(i=0;

  printf(“变量x[%d]的近似根是%f”,i,x[i]);

  printf(“\n”);

提醒 具体使用迭代法求根时应注意以下两种可能发生的情况:

●如果方程无解,算法求出的近似根序列就不会收敛,迭代过程会变成死循环,因此在使用迭代算法前应先考察方程是否有解,并在程序中对迭代的次数给予限制;

●方程虽然有解,但迭代公式选择不当,或迭代的初始近似根选择不合理,也会导致迭代失败。

6.3穷举搜索法

  穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,并从众找出那些符合要求的候选解作为问题的解的方法。

【例6-2】找出n个自然数(1,2,3,…,n)中r个数的组合。

例如,当n=5,r=3时,所有组合为:

543

542

541

532

531

521

432

431

421

321

问题分析求n个数中r个数的组合,其中每r个数中,数不能相同。

另外,任何两组组合的数,所包含的数也不应相同。

例如,5、4、3与3、4、5。

为此,约定前一个数应大于后一个数。

将上述两条不允许为条件,当r=3时,可用三重循环进行搜索

程序:

constintn=5,r=3;

inti,j,k,t;

t=0;

for(i=n;

i>

=r;

i--)

for(j=i-1;

j>

=r-1;

j--)

for(k=j-1;

k>

=1;

{

t=t+1;

printf(“%4d%4d%4d”,i,j,k);

想一想 假如有n=9,r=5此问题的求解会发生什么变化?

知识点播 用穷举搜索法解决问题一般都有一个问题,当r变化时,循环重数改变,这就影响了这一问题的解的通用性,即没有一般性。

但是,很多情况下穷举搜索法还是常用的。

提醒 用穷举搜索法解决问题,最重要的因素就是确定某种方法来确定所有的候选解。

下面用一个示例来加以说明。

【问题】背包问题

问题描述有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和最大。

问题分析设n个物品的重量和价值分别存储于数组w[]和v[]中,限制重量为tw。

考虑一个n元组(x0,x1,…,xn-1),其中xi=0表示第i个物品没有选取,而xi=1则表示第i个物品被选取。

显然这个n元组等价于一个选择方案。

用枚举法解决背包问题,需要枚举所有的选取方案,而根据上述方法,我们只要枚举所有的n元组,就可以得到问题的解。

显然,每个分量取值为0或1的n元组的个数共为2n个。

而每个n元组其实对应了一个长度为n的二进制数,且这些二进制数的取值范围为0~2n-1。

因此,如果把0~2n-1分别转化为相应的二进制数,则可以得到我们所需要的2n个n元组。

【算法】

  maxv=0;

  for(i=0;

2n;

i++)

  {

B[0..n-1]=0;

  把i转化为二进制数,存储于数组B中;

  temp_w=0;

  temp_v=0;

  for(j=0;

j  

if(B[j]==1)

  {

temp_w=temp_w+w[j];

  temp_v=temp_v+v[j];

  }

  if((temp_w<

=tw)&

&

(temp_v>

maxv))

maxv=temp_v;

  保存该B数组;

  }

试一试读者自行将此问题的解决思路用C语言实现。

6.4递推法

递推法的解决问题是指在前面已知的一个或几个结果的基础上推导出下一个结果,从而推导出最终解的解决方法。

【例6-3】有一数列,第一个数是2,第二个数是3,第三个是前两个数之和,以后每个数都是其前两个数之和,要求输出该数列的前N(10)项。

问题分析显然这是一个典型的递推问题,从第三个数开始,每个数都是其前两个数之和,即要想知道第N个数,必须先知道第N-2个和第N-1个数,然后才能求第N个数。

这样的问题可以利用循环结构,从已知数开始,循环计算,直到计算出第N个数。

此例可以先把已知两个数分别放置到变量A和B中,显示A和B,再计算C=A+B得到第三个数,输出第三个数C;

要得到第四个数,应该把C和B相加,但是为了减少变量的使用和简化程序,我们可以把B的值移到A中(A中原来的数据已经无用),让出B变量,再把C中的数据移到B中,再计算C=A+B,输出C的值,得到第四个数;

再把B的值移到A中,……,如此循环,可以得到数列的N个数。

基本算法与程序实现:

#defineN10

inti,A=2,B=3,C;

C=A+B;

printf(“%4d\n%4d\n”,A,B);

for(i=3;

=N;

{

printf(“%4d\n”,C);

A=B;

B=C;

6.5递归法

递归法是将问题递推到比原问题更简单的问题上求解,然后再回归到原问题上的一种解决问题的方法,是“递推”和“回归”两个部分的简称。

知识点播 递推:

就是为得到问题的解,将它推到比原问题简单的问题的求解。

我们先看看下面的数学中的递归定义例子:

 

比如:

为求N!

,先求(N-1)!

,因为(N-1)!

更接近以知解0!

=1;

再看看下面的过程:

3!

=3*2!

2!

=2*1!

1!

=1*0!

0!

提醒 

●递推应有终止之时。

例如,N!

,当N=0时,0!

=1为递推的终止条件,在此条件下,问题的解是明确的,缺少终止条件算法会失败。

●简单问题表示离递推终止条件更接近的问题。

简单问题与原问题其解的算法是一致的,其差别主要反映在参数值上。

与(N-1)!

其参数差1。

参数的变化,使问题递推到有明确解的问题上。

知识点播 回归:

指简单问题得到解后,回归到原问题的解上来。

例如:

当计算完(N-1)!

后,回归计算N*(N-1)!

,即得N!

注意:

回归是递推的返回过程。

【例6-4】N!

的递归函数定义。

源程序参考:

longf(inti)

if(i==0)

return1;

else

returni*(i-1);

试一试

Fibonacci数定义如下:

F(0)=0;

F

(1)=1;

F(N)=F(N-1)+F(N-2)(N>

1时)

6.6回溯法

回溯法是一个既带有系统性又带有跳跃性的的搜索算法。

知识点播回溯法的基本思想是在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。

算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。

如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。

否则,进入该子树,继续按深度优先的策略进行搜索。

回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。

而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。

这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。

算法分析

1、问题的解空间:

应用回溯法解问题时,首先应明确定义问题的解空间。

问题的解空间应到少包含问题的一个(最优)解。

2、运用回溯法解题通常包含以下三个步骤:

(1)针对所给问题,定义问题的解空间;

(2)确定易于搜索的解空间结构;

(3)以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索;

3、递归回溯:

由于回溯法是对解空间的深度优先搜索,因此在一般情况下可用递归函数来实现。

回溯法基本算法如下:

try(inti)

if(i>

n)输出结果

else

forj=下界to上界

x[i]=h[j];

if可行{满足限界函数和约束条件}

{置值;

try(i+1);

}

说明:

i是递归深度;

n是深度控制,即解空间树的的高度;

可行性判断有两方面的内容:

不满约束条件则剪去相应子树;

若限界函数越界,也剪去相应子树;

两者均满足则进入下一层。

【例6-5】采用回溯法找出从自然数1,2,…,n中任取r个数的所有组合。

问题描述设n=5,r=3,并将找到的组合以从小到大顺序存于a[0],a[1],…,a[r-1]中,组合的元素满足以下性质:

  

(1)a[i+1]>

a[i],后一个数字比前一个大;

  

(2)a[i]-i<

=n-r+1。

问题分析首先放弃组合数个数为r的条件,候选组合从只有一个数字1开始。

因该候选解满足除问题规模之外的全部条件,扩大其规模,并使其满足上述条件

(1),候选组合改为1,2。

继续这一过程,得到候选组合1,2,3。

该候选解满足包括问题规模在内的全部条件,因而是一个解。

在该解的基础上,选下一个候选解,因a[2]上的3调整为4,以及以后调整为5都满足问题的全部要求,得到解1,2,4和1,2,5。

由于对5不能再作调整,就要从a[2]回溯到a[1],这时,a[1]=2,可以调整为3,并向前试探,得到解1,3,4。

重复上述向前试探和向后回溯,直至要从a[0]再回溯时,说明已经找完问题的全部解。

按上述思想写成程序如下:

  【程序】

  #defineMAXN100

inta[MAXN];

voidcomb(intm,intr)

{inti,j,k;

clrscr();

for(i=0;

a[i]=i+1;

i=r-1;

j=i;

do{

if(a[i]-i<

=m-r+1)

for(k=i+1;

k<

k++)

a[k]=a[k-1]+1;

for(k=0;

printf("

%4d"

a[k]);

\n"

);

a[i]++;

continue;

else

{i=j;

if(i==0)

return;

a[--i]++;

}while

(1);

{comb(7,5);

想一想 回溯法与递归法在解决问题的思路上是不是相同的,他们有何区别和联系?

6.7贪婪法

贪婪法是一种不追求最优解,只希望得到较为满意解的方法。

贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。

贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,所以贪婪法不要回溯。

知识点播平时购物找钱时,为使找回的零钱的硬币数最少,不考虑找零钱的所有各种方案,而是从最大面值的币种开始,按递减的顺序考虑各币种,先尽量用大面值的币种,当不足大面值币种的金额时才去考虑下一种较小面值的币种。

这就是在使用贪婪法。

这种方法在这里总是最优,是因为银行对其发行的硬币种类和硬币面值的巧妙安排。

如只有面值分别为1、5和11单位的硬币,而希望找回总额为15单位的硬币。

按贪婪算法,应找1个11单位面值的硬币和4个1单位面值的硬币,共找回5个硬币。

但最优的解应是3个5单位面值的硬币。

  【例6-6】装箱问题

问题描述装箱问题可简述如下:

设有编号为0、1、…、n-1的n种物品,体积分别为v0、v1、…、vn-1。

将这n种物品装到容量都为V的若干箱子里。

约定这n种物品的体积均不超过V,即对于0≤i<n,有0<vi≤V。

不同的装箱方案所需要的箱子数目可能不同。

装箱问题要求使装尽这n种物品的箱子数要少。

问题分析若考察将n种物品的集合分划成n个或小于n个物品的所有子集,最优解就可以找到。

但所有可能划分的总数太大。

对适当大的n,找出所有可能的划分要花费的时间是无法承受的。

为此,对装箱问题采用非常简单的近似算法,即贪婪法。

该算法依次将物品放到它第一个能放进去的箱子中,该算法虽不能保证找到最优解,但还是能找到非常好的解。

不失一般性,设n件物品的体积是按从大到小排好序的,即有v0≥v1≥…≥vn-1。

如不满足上述要求,只要先对这n件物品按它们的体积从大到小排序,然后按排序结果对物品重新编号即可。

算法描述:

  {输入箱子的容积;

  输入物品种数n;

  按体积从大到小顺序,输入各物品的体积;

  预置已用箱子链为空;

  预置已用箱子计数器box_count为0;

n;

i++) 

{

从已用的第一只箱子开始顺序寻找能放入物品i的箱子j;

  if(已用箱子都不能再放物品i)

  {另用一个箱子,并将物品i放入该箱子;

  box_count++;

  }

  else

  将物品i放入箱子j;

  上述算法能求出需要的箱子数box_count,并能求出各箱子所装物品。

下述程序为上述算法的C语言描述。

程序描述每只箱子所装物品用链表来表示,链表首结点指针存于一个结构中,结构记录尚剩余的空间量和该箱子所装物品链表的首指针。

另将全部箱子的信息也构成链表。

以下是按以上算法编写的程序。

【程序】

#include<

math.h>

stdio.h>

typedefstructele

intvno;

/*存放箱子的编号*/

structele*link;

/*链表指针*/

}ELE;

typedefstructhnode

intremainder;

/*记录尚剩余的空间量*/

ELE*head;

/*该箱子所装物品链表的首指针*/

structhnode*next;

/*指向下一个装有物品的箱子*/

}HNODE;

voidmain()

{intn,i,box_count,box_volume,*a;

HNODE*box_h,*box_t,*j;

ELE*p,*q;

输入箱子容积\n"

scanf("

%d"

&

box_volume);

输入物品种数\n"

n);

a=(int*)malloc(sizeof(int)*n);

请按体积从大到小顺序输入各物品的体积:

"

for(i=0;

a[i]);

box_h=box_t=NULL;

/*预置已用箱子链为空*/

box_count=0;

p=(ELE*)malloc(sizeof(ELE));

p->

vno=i;

for(j=box_h;

j!

=NULL;

j=j->

next)

if(j->

remainder>

=a[i])break;

if(j==NULL)/*已用箱子都不能再放物品i*/

{/*另用一个箱子,并将物品i放入该箱子*/

j=(HNODE*)malloc(sizeof(HNODE));

j->

remainder=box_volume-a[i];

head=NULL;

if(box_h==NULL)box_h=box_t=j;

elsebox_t=box_t->

next=j;

next=NULL;

box_count++;

elsej->

remainder-=a[i];

/*将物品i放入箱子j*/

for(q=j->

head;

q!

=NULL&

q->

link!

q=q->

link);

if(q==NULL)/*新启用的箱子*/

p->

link=j->

head=p;

{p->

link=NULL;

q->

link=p;

共使用了%d只箱子"

box_count);

各箱子装物品情况如下:

for(j=box_h,i=1;

next,i++)

第%2d只箱子还剩余容积%4d,所装物品有;

i,j->

remainder);

for(p=j->

p!

p=p->

link)

p->

vno+1);

设有6种物品,它们的体积分别为:

60、45、35、20、20和20单位体积,箱子的容积为100个单位体积。

按上述算法的程序计算,需三只箱子,各箱子所装物品分别为:

第一只箱子装物品1、3;

第二只箱子装物品2、4、5;

第三只箱子装物品6。

想一想 上述问题的最优解是什么?

贪婪法寻求的问题的解是不是原问题的最优解。

习题6

1.程序填空(请根据指定程序的功能,在空格处将程序补充完整)

从n种不同总量,不同价值的物品中选取一部分物品,要求在不超过限定重量limw的前提下,使被选取的物品的总价值最大。

这里约定limw是不超过n种物品的总量的总和,也没有一种物品的总量超过limw,并且各物品的价值都大于0。

程序中,n种物品被顺序编号为0、1、2、3、...、n-1。

#include<

#defineN3

doublelimw;

intopts[N];

/*临时存储最佳选择方案,当opts[i]为1时,物品i在解中*/

structelem{

doubleweight;

doublevalue;

}a[N];

/*物品重量和价值信息*/

intk,n;

struct{

intflag;

/*物品的状态:

0,不选;

1,考虑;

2,曾被选中*/

doubletw;

/*已达到的重量*/

doubletv;

/*期望的总价值*/

}twv[N];

/*当前候选解总各物品的考虑状态及候选解的状态*/

doublemaxv,find(structelem*,int);

printf(“Enternumberofmater.”);

scanf(“%d”,&

n)

printf(“E

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

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2