算法研究.docx
- 文档编号:4459256
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:73
- 大小:56.77KB
算法研究.docx
《算法研究.docx》由会员分享,可在线阅读,更多相关《算法研究.docx(73页珍藏版)》请在冰豆网上搜索。
算法研究
算法学习
(一)
作者:
佚名文章来源:
本站原创点击数:
3253更新时间:
2004-5-15
一、迭代法
迭代法是用于求方程或方程组近似根的一种常用的算法设计方法。
设方程为f(x)=0,用
某种数学方法导出等价的形式x=g(x),然后按以下步骤执行:
(1) 选一个方程的近似根,赋给变量x0;
(2) 将x0的值保存于变量x1,然后计算g(x1),并将结果存于变量x0;
(3) 当x0与x1的差的绝对值还小于指定的精度要求时,重复步骤
(2)的计算。
若方程有根,并且用上述方法计算出来的近似根序列收敛,则按上述方法求得的x0就认
为是方程的根。
上述算法用C程序的形式表示为:
【算法】迭代法求方程的根
{ x0=初始近似根;
do {
x1=x0;
x0=g(x1); /*按特定的方程计算新的近似根*/
} while ( fabs(x0-x1)>Epsilon);
printf(“方程的近似根是%f\n”,x0);
}
迭代算法也常用于求方程组的根,令
X=(x0,x1,…,xn-1)
设方程组为:
xi=gi(X) (I=0,1,…,n-1)
则求方程组根的迭代算法可描述如下:
【算法】迭代法求方程组的根
{ for (i=0;i x[i]=初始近似根; do { for (i=0;i y[i]=x[i]; for (i=0;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>Epsilon); for (i=0;i printf(“变量x[%d]的近似根是 %f”,I,x[i]); printf(“\n”); } 具体使用迭代法求根时应注意以下两种可能发生的情况: (1) 如果方程无解,算法求出的近似根序列就不会收敛,迭代过程会变成死循 环,因此在使用迭代算法前应先考察方程是否有解,并在程序中对迭代的次数给予限 制; (2) 方程虽然有解,但迭代公式选择不当,或迭代的初始近似根选择不合理,也 会导致迭代失败。 二、穷举搜索法 穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,并 从众找出那些符合要求的候选解作为问题的解。 【问题】 将A、B、C、D、E、F这六个变量排成如图所示的三角形,这六个变量分别取 [1,6]上的整数,且均不相同。 求使三角形三条边上的变量之和相等的全部解。 如图就 是一个解。 程序引入变量a、b、c、d、e、f,并让它们分别顺序取1至6的证书,在它们互不相同的 条件下,测试由它们排成的如图所示的三角形三条边上的变量之和是否相等,如相等即 为一种满足要求的排列,把它们输出。 当这些变量取尽所有的组合后,程序就可得到全 部可能的解。 细节见下面的程序。 【程序1】 # include void main() { int a,b,c,d,e,f; for (a=1;a<=6;a++) for (b=1;b<=6;b++) { if (b==a) continue; for (c=1;c<=6;c++) { if (c==a)||(c==b) continue; for (d=1;d<=6;d++) { if (d==a)||(d==b)|| (d==c) continue; for (e=1;e<=6;e++) { if (e==a)||(e==b)||(e==c)||(e==d) continue; f=21-(a+b+c+d+e); if ((a+b+c==c+d+e))&&(a+b+c==e+f+a)) { printf(“%6d,a); printf(“%4d%4d”,b,f); printf(“%2d%4d%4d”,c,d,e); scanf(“%*c”); } } } } } } 按穷举法编写的程序通常不能适应变化的情况。 如问题改成有9个变量排成三角形,每条 边有4个变量的情况,程序的循环重数就要相应改变。 对一组数穷尽所有排列,还有更直接的方法。 将一个排列看作一个长整数, 则所有排列对应着一组整数。 将这组整数按从小到大的顺序排列排成一个整数,从对应 最小的整数开始。 按数列的递增顺序逐一列举每个排列对应的每个整数,这能更有效地 完成排列的穷举。 从一个排列找出对应数列的下一个排列可在当前排列的基础上作部分 调整来实现。 倘若当前排列为1,2,4,6,5,3,并令其对应的长整数为124653。 要寻 找比长整数124653更大的排列,可从该排列的最后一个数字顺序向前逐位考察,当发现 排列中的某个数字比它前一个数字大时,如本例中的6比它的前一位数字4大,这说明还 有对应更大整数的排列。 但为了顺序从小到大列举出所有的排列,不能立即调整得太 大,如本例中将数字6与数字4交换得到的排列126453就不是排列124653的下一个排列。 为了得到排列124653的下一个排列,应从已经考察过的那部分数字中选出比数字大,但 又是它们中最小的那一个数字,比如数字5,与数字4交换。 该数字也是从后向前考察过 程中第一个比4大的数字。 5与4交换后,得到排列125643。 在前面数字1,2,5固定的情 况下,还应选择对应最小整数的那个排列,为此还需将后面那部分数字的排列顺序颠 倒,如将数字6,4,3的排列顺序颠倒,得到排列1,2,5,3,4,6,这才是排列1,2, 4,6,5,3的下一个排列。 按以上想法编写的程序如下。 【程序2】 # include # define SIDE_N 3 # define LENGTH 3 # define VARIABLES 6 int A,B,C,D,E,F; int *pt[]={&A,&B,&C,&D,&E,&F}; int *side[SIDE_N][LENGTH]={&A,&B,&C,&C,&D,&E,&E,&F,&A}; int side_total[SIDE_N]; main{} { int i,j,t,equal; for (j=0;j *pt[j]=j+1; while (1) { for (i=0;i { for (t=j=0;j t+=*side[i][j]; side_total[i]=t; } for (equal=1,i=0;equal&&i if (side_total[i]! =side_total[i+1] equal=0; if (equal) { for (i=1;i printf(“%4d”,*pt[i]); printf(“\n”); scanf(“%*c”); } for (j=VARIABLES-1;j>0;j--) if (*pt[j]>*pt[j-1]) break; if (j==0) break; for (i=VARIABLES-1;i>=j;i--) if (*pt[i]>*pt[i-1]) break; t=*pt[j-1];* pt[j-1] =* pt[i]; *pt[i]=t; for (i=VARIABLES-1;i>j;i--,j++) { t=*pt[j]; *pt[j] =* pt[i]; *pt[i]=t; } } } 从上述问题解决的方法中,最重要的因素就是确定某种方法来确定所有的候选解。 下面 再用一个示例来加以说明。 【问题】 背包问题 问题描述: 有不同价值、不同重量的物品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;i<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数组; } } } 三、递推法 递推法是利用问题本身所具有的一种递推关系求问题解的一种方法。 设要求 问题规模为N的解,当N=1时,解或为已知,或能非常方便地得到解。 能采用递推法构造 算法的问题有重要的递推性质,即当得到问题规模为i-1的解后,由问题的递推性质,能 从已求得的规模为1,2,…,i-1的一系列解,构造出问题规模为I的解。 这样,程序可 从i=0或i=1出发,重复地,由已知至i-1规模的解,通过递推,获得规模为i的解,直至 得到规模为N的解。 【问题】 阶乘计算 问题描述: 编写程序,对给定的n(n≦100),计算并输出k的阶乘k! (k=1,2,…, n)的全部有效数字。 由于要求的整数可能大大超出一般整数的位数,程序用一维数组存储长整数,存储长整 数数组的每个元素只存储长整数的一位数字。 如有m位成整数N用数组a[ ]存储: N=a[m]×10m-1+a[m-1]×10m-2+ … +a[2]×101+a[1]×100 并用a[0]存储长整数N的位数m,即a[0]=m。 按上述约定,数组的每个元素存储k的阶乘 k! 的一位数字,并从低位到高位依次存于数组的第二个元素、第三个元素……。 例如, 5! =120,在数组中的存储形式为: 3 0 2 1 …… 首元素3表示长整数是一个3位数,接着是低位到高位依次是0、2、1,表示成整数120。 计算阶乘k! 可采用对已求得的阶乘(k-1)! 连续累加k-1次后求得。 例如,已 知4! =24,计算5! ,可对原来的24累加4次24后得到120。 细节见以下程序。 # include # include # define MAXN 1000 void pnext(int a[ ],int k) { int *b,m=a[0],i,j,r,carry; b=(int * ) malloc(sizeof(int)* (m+1)); for ( i=1;i<=m;i++) b[i]=a[i]; for ( j=1;j<=k;j++) { for ( carry=0,i=1;i<=m;i++)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 研究