C语言的六种常用算法
C语言常用算法集合

1.定积分近似计算:/*梯形法*/double integral(double a,double b,long n) { long i;double s,h,x;h=(b-a)/n;s=h*(f(a)+f(b))/2;x=a;for(i=1;i<n;i++){x+=h;s+=h*f(x) ;}return(s);}/*矩形法*/double integral(double a,double b,long n) { long i;double t=0,h,x;h=(b-a)/n;x=a;for(i=0;i<n;i++){t+=h*f(x);x+=h;}return(t);}2. 生成斐波那契数列:/*直接计算*/int fib(int n){ int i,f1=1,f2=1,f;for(i=3;i<=n;i++){f=f1+f2;f1=f2;f2=f;}if(n==1||n==2) return 1;else return f;}/*递归调用*/void fib(int n,int*s){ int f1,f2;if(n==1||n==2) *s=1;else{ fib(n-1,&f1);fib(n-2,&f2);*s=f1+f2;}}3.素数的判断:/*方法一*/for (t=1,i=2;i<n; i++)if(n%i==0) t=0;if(t) printf("%d is prime",n);/*方法二*/for (t=1,i=2;i<n&&t; i++)if(n%i==0) t=0;if(t) printf("%d is prime",n);/*方法三*/for (i=2;i<n; i++)if(n%i==0) break;if(i==n) printf("%d is prime",n); /*方法四*/for(t=1,i=2; i<=(int)sqrt(n); i++)if(n%i==0){t=0;break;}if(t) printf("%d is prime",n);4.反序数:/*求反序数*/long fan(long n){ long k;for(k=0;n>0;n/=10)k=10*k+n%10;return k;}/*求回文数*/int f(long n){ long k,m=n;for(k=0;n>0;n/=10)k=10*k+n%10;if(m==k) return 1;return 0;}/*求整数位数*/int f(long n){ int count;for(count=0;n>0;n/=10)count++;return count;}5.求最大公约数:/*方法一*/int gcd(int x,int y){ int z;z=x<y?x:y;while(!(x%z==0&&y%z==0))/*x%z||y%z*/ z--;return z;}/*方法二*/int gcd(int x,int y){int r;while((r=x%y)!=0){x=y;y=r;}return y;}/*方法三*/int gcd(int a ,int b){ int r ;if((r=a%b)==0)return b;elsereturn gcd(b,r);}6.数组常用算法:查找:/*线性查找*/int find(int num,int x[],int key){ int i,m=-1;for(i=0;i<num;i++)if(x[i]==key){m=i;break;}return m;}/*折半查找*/int find(int x[],int num,int key){ int m=-1,low=0,high=num-1,mid;while(low<=high){mid=(low+high)/2;if(x[mid]==key){m=mid;break;}else if(x[mid]>key) high=mid-1;else low=mid+1;}return m;}/*折半查找(递归)*/int b_search(int x[ ],int low,int high,int key) {int mid;mid=(low+high)/2;if(x[mid]==key) return mid;if(low>=high) return -1;else if(key<x[mid])return b_search(x,low,mid-1,key);elsereturn b_search(x,mid+1,high,key); }/*寻找子串*/int find(char *s1,char *s2){ int i,k=0;while(s1[i]==s2[i]) i++;if(s2[i]==0) return k;s1++;k++;return -1;}分词:/*方法一*/void fen(char s[][10],char str){ int i,j,k;for(i=0,j=0,k=0;str[i]!=0;i++)if(isalpha(a[i]))s[j][k++]=str[i];else {s[j][k]=0;k=0;j++;}}}/*方法二*/#include<stdio.h>#include<string.h>void main(){ int i=0,n=0;char s[80],*p;strcpy(s,"It is a book.");for(p=s;p!='\0';p++)if(*p=='')i=0;elseif(i==0){n++;i=1;}printf("%d\n",n);getch();}排序:/*插入法排序*/void sort(int a[],int n){ int i,j,t;for(i=1;i<n;i++){t=a[i];for(j=i-1;j>=0&&t<a[j];j--)a[j+1]=a[j];a[j]=t;}}/*归并排序*/#define x 10#define y 10void com(int *a,int *b,int *c){ int i,j,k;for(i=0,j=0,k=0;i<=x&&j<=y;){if(a[i]<b[j]){c[k++]=a[i];i++;}else{c[k++]=b[j];j++;}}if(i<x) for(k=k-1;i<x;i++)c[k++]=a[i];if(j<x) for(k=k-1;j<y;j++)c[k++]=a[j]; }/*交换法排序1 冒泡排序*/void sort(int a[],int n){ int i,j,t,flag;for(i=0;i<n-1;i++){flag=1;for(j=0;j<n-1-i;j++)if(a[j]>a[j+1]){t=a[j];a[j]=a[j+1];a[j+1]=t;flag=0;}if(flag) break;}}/*交换法排序2*/void sort(int a[],int n){ int i,j,t;for(i=0;i<n-1;i++)for(j=i+1;j<n;j++)if(a[i]>a[j]){t=a[i];a[i]=a[j];a[j]=t;}}/*选择法排序*/void sort(int a[],int n){ int i,j,point,t;for(i=0;i<n-1;i++){point=i;for(j=i+1;j<n;j++)if(a[point]<a[j]) point=j;if(point!=i){t=a[point];a[point]=a[i];a[i]=t;}}}7.一元非线性方程求根:/*牛顿迭代法求函数跟*/#include <stdio.h>#include <math.h>int main(void){ double x,x1,eps=1e-6,f,f1; /*误差为eps*/x=1.0; /*x=1.0是初值*/do{x1=x;f=6-x1*(5-x1*(4-3*x1)); /*f为f(x)函数*/f1=-5+x1*(8-9*x1); /*f1为f(x)的导函数*/x=x1-f/f1;f=6-x*(5-x*(4-3*x));}while(fabs(f)>=eps &&fabs(x-x1)>=eps);printf("x=%f",x);}/*二分法求函数跟*/#include <stdio.h>#include <math.h>double f(double x){ return 6-x*(5-x*(4-3*x)); /*f(x)函数*/}int main(void){ double a,b,c,x,eps=1e-6;do{scanf("%lf%lf",&a,&b);}while(f(a)*f(b)>0);if(fabs(f(a))<1e-6)x=a;else if (fabs(f(b))<1e-6)x=b;else {c=(b+a)/2;while(fabs(f(c))>eps&&fabs(b-a)>eps){if(f(a)*f(c)<0)b=c;elsea=c;c=(b+a)/2;}x=c;}printf("x=%f",x);}/*弦截法求函数跟*/c=(a*f(b)-b*f(a))/ (f(b)-f(a));while(fabs(f(c))>eps){if(f(a)*f(c)<0)b=c;elsea=c;c=(a*f(b)-b*f(a))/ (f(b)-f(a));}#include <stdio.h>void f();int main(void){ int x, loop=0;do{for(x=1;x<5;x++) {int x=2;printf("%d",x);}printf("%d ",x);f();loop++;}while(loop<1);getch();}void f(){ printf("%d",x++); }8.汉诺塔:#include<stdio.h>void Hanoi(int n, char A, char B, char C){if(n==1)printf("\n move %d from %c to %c",n,A,C);else{Hanoi(n-1,A,C,B);printf("\nmove %d from %c to %c",n,A,C);Hanoi(n-1,B, A, C);}}int main(void){ Hanoi(3,'A','B','C');getch();}9.建立链表:NODE *creat(void) /* void表示无参函数*/{NODE *head=NULL,*p1=NULL,*p2=NULL;long num;unsigned score;int n=0;do{scanf(“%ld%u”,&num,&score);if(num==0) break;n++;p1=(NODE *)malloc(sizeof(NODE));p1->data.num=num,p1->data.score=score;p1->next=NULL;if(n==1)head=p2=p1;else{p2->next=p1;p2=p1;}}while(1);return head;}10.级数的近似计算:#include <stdio.h>#include <math.h>int main(void){ double s=1,a=1,x,eps,f;int n,m;printf("input x and eps:");scanf ("%lf%lf",&x,&eps);for(n=1;fabs(a)>eps; n++){for(f=1,m=1;m<=n;m++)f*=m;a=pow(x,n)/f;s+=a;}printf("%f",s);}。
C语言常用算法

1.迭代法:
一般的一元五次方程或更高次的方程,以及几乎所有的微分方程、超越方程问题都无法用解析方法通过求根公式来求解,人们只能用数值方法求其近似值。
用事先估计的一个根的初始值X0,通过迭代算式X K+1=G(X K)求出一个近似的X1,再由求出X2,从而或得一个求解序列{ X0, X1, X2,…..X n,…}来逼近方程f(x)=0根。
这种求解过程成为迭代。
X1 x2=G(x1)
X3=G(x2)
X4=G(x3)
………
Xn=G(XN-1)
fabs(xn- xn-1)<1e-6
Xn+1=G(XN)
2.递归法:
递归是指一个过程直接或间接的调用它自身,递归过程必须有一个终止条件
3.递推法:
算法从递推的初始条件出发,应用递推公式对问题进行求解。
如Fibonacci 数列存在递推关系:
F(1)=1, F(2)=1, F(3)=2,
F(n)= F(n-1)+ F(n-2), (n>2)
若需求第30项的值,则依据公式,从初始条件F(1)=1,F(2)=1出发,逐步求出F(3),F(4),……,直到求出F(30)。
C语言用六种方法求定积分

C语言用六种方法求定积分C语言中求定积分的方法主要有以下六种:基本公式法、数值积分法、Laplace变换法、微积分概念法、数值积分法和Monte Carlo方法。
下面将详细介绍每种方法的原理和实现。
1.基本公式法:基本公式法是求解定积分的最基本方法,根据不同函数的特点和性质,利用已知的积分公式进行求解。
例如,对于一次函数和常数函数,可以使用基本公式法求解。
2.数值积分法:数值积分法是通过将定积分转化为数值计算问题来求解。
常用的数值积分方法有矩形法、梯形法和辛普森法等。
这些方法基于将求积分区间分割成若干个小区间,然后在每个小区间上近似计算出函数的积分值,再将这些积分值加总得到最终结果。
3. Laplace变换法:Laplace变换法是一种利用Laplace变换求解微分方程的方法,也可以用来求解定积分。
通过将被积函数进行Laplace变换,然后利用Laplace变换公式求解积分,最后再求出反变换得到结果。
4.微积分概念法:微积分概念法是通过将定积分定义为函数曲线下的面积来求解。
具体做法是将被积函数图像与坐标轴围成的面积分为若干个小的矩形、梯形或曲线段以及一个小的区域。
然后根据图形的几何性质进行近似计算,将这些小面积相加得到最终结果。
5.数值积分法:数值积分法也是一种基于数值计算的方法,但与前面提到的数值积分法不同,它通过构造一系列特定形式的插值函数对被积函数进行逼近,然后计算插值函数的积分值来近似求解定积分。
常用的数值积分法有牛顿-科特斯公式和高斯-勒让德公式。
6. Monte Carlo方法:Monte Carlo方法是一种基于统计随机性的数值积分方法,它通过随机抽样来进行数值求解。
具体做法是在被积函数图像下随机抽取一系列点,根据这些随机点的坐标和函数值来估计函数的积分值。
通过对多次随机抽样的结果取平均可以得到定积分的近似值。
以上六种方法都可以用C语言来实现,具体的实现方法可以根据具体问题的特点和要求选择合适的算法和数据结构,然后编写相应的代码实现。
C语言常用算法总结

C语言常用算法总结1、冒泡排序算法:冒泡排序是一种简单的排序算法,它重复地遍历要排序的序列,一次比较两个相邻的元素如果他们的顺序错误就把他们交换过来。
时间复杂度为O(n^2)。
2、快速排序算法:快速排序是一种基于分治的排序算法,通过递归的方式将数组划分为两个子数组,然后对子数组进行排序最后将排好序的子数组合并起来。
时间复杂度为O(nlogn)。
3、插入排序算法:插入排序是一种简单直观的排序算法,通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描找到相应位置并插入。
时间复杂度为O(n^2)。
4、选择排序算法:选择排序是一种简单的排序算法,每次循环选择未排序部分的最小元素,并放置在已排序部分的末尾。
时间复杂度为O(n^2)。
5、归并排序算法:归并排序是一种稳定的排序算法,基于分治思想,将数组递归地分为两个子数组,将子数组排序后再进行合并最终得到有序的数组。
时间复杂度为O(nlogn)。
6、堆排序算法:堆排序是一种基于完全二叉堆的排序算法,通过构建最大堆或最小堆,然后依次将堆顶元素与末尾元素交换再调整堆,得到有序的数组。
时间复杂度为O(nlogn)。
7、二分查找算法:二分查找是一种在有序数组中查找目标元素的算法,每次将待查找范围缩小一半,直到找到目标元素或范围为空。
时间复杂度为O(logn)。
8、KMP算法:KMP算法是一种字符串匹配算法,通过利用模式字符串的自重复性,避免不必要的比较提高匹配效率。
时间复杂度为O(m+n),其中m为文本串长度,n为模式串长度。
9、动态规划算法:动态规划是一种通过将问题分解为子问题,并通过组合子问题的解来求解原问题的方法。
动态规划算法通常使用内存空间来存储中间结果,从而避免重复计算。
时间复杂度取决于问题规模。
10、贪心算法:贪心算法是一种通过选择局部最优解来构建全局最优解的算法并以此构建最终解。
时间复杂度取决于问题规模。
11、最短路径算法:最短路径算法用于求解图中两个节点之间的最短路径,常见的算法包括Dijkstra算法和Floyd-Warshall算法。
C语言算法全总结

C语言算法全总结C语言是一种广泛应用于计算机科学领域的编程语言,具有高效、可移植和灵活的特点。
在程序设计中,算法是解决问题的一系列有序步骤,可以通过C语言来实现。
本文将为您总结C语言中常用的算法,包括排序算法、查找算法和图算法。
一、排序算法排序算法是将一组元素按照特定的顺序重新排列的算法。
常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序和归并排序。
这些算法的核心思想是通过比较和交换元素的位置来进行排序。
1.冒泡排序冒泡排序通过多次比较和交换相邻元素的位置来实现排序。
它的基本思想是将最大的元素不断地往后移动,直到整个序列有序。
2.选择排序选择排序通过每次选择最小的元素来实现排序。
它的基本思想是通过比较找到最小元素的位置,然后将其与第一个元素交换,接着在剩下的元素中继续找到最小元素并进行交换,如此重复直到整个序列有序。
3.插入排序插入排序通过构建有序序列,对未排序序列逐个元素进行插入,从而实现排序。
它的基本思想是将当前元素插入到前面已经排好序的序列中的适当位置。
4.快速排序快速排序是一种分治算法,通过选择一个基准元素,将其他元素划分为小于基准元素和大于基准元素的两部分,然后递归地对这两部分进行排序,最终实现整个序列有序。
5.归并排序归并排序也是一种分治算法,将序列分成两个子序列,分别对这两个子序列进行排序,然后将排序后的子序列合并成一个有序序列,从而达到整个序列有序的目的。
二、查找算法查找算法是在一个数据集合中寻找特定元素的算法。
常见的查找算法包括线性查找、二分查找和散列查找。
这些算法的核心思想是通过比较元素的值来确定待查找元素的位置。
1.线性查找线性查找是从数据集合的开头开始,依次比较每个元素的值,直到找到目标元素为止。
它的时间复杂度为O(n),其中n为数据集合的大小。
2.二分查找二分查找是针对有序序列进行查找的算法,它的基本思想是通过不断缩小查找范围,将目标元素与中间元素进行比较,从而确定待查找元素的位置。
C语言常用算法

} 插入法排序的要领就是每读入一个数立即插入到最终存放的数组中,每次插入都使得该数组有序。
例 2、任意读入 10 个整数,将其用插入法按降序排列后输出。
#define n 10
main()
{int a[n],i,j,k,x;
scanf("%d",&a[0]); /*读入第一个数,直接存到 a[0]中*/
if(b>c) { t=b; b=c; c=t; } printf("%d,%d,%d\n",a,b,c);}
2.累加
C 语言常用算法
累加算法的要领是形如“s=s+A”的累加式,此式必须出现在循环中才能被反复执行,从而
实现累加功能。“A”通常是有规律变化的表达式,s 在进入循环前必须获得合适的初值,通常为 0。
C 语言常用算法
②除第 1 个数以外,再从其余 n-1 个数中找出最小数(即 n 个数中的次小数)的下标,将此数 与第 2 个数交换位置;
③重复步骤①n-1 趟,即可完成所求。
例 1、任意读入 10 个整数,将其用选择法按升序排列后输出。
#define n 10
main()
{int a[n],i,j,k,t;
3.查找
(1)顺序查找(即线性查找) 顺序查找 的思路是:将待 查找的量与数组中 的每一个元素进 行比较,若有一个 元素与之相等
则找到;若没有一个元素与之相等则找不到。 例 1、任意读入 10 个数存放到数组 a 中,然后读入待查找数值,存放到 x 中,判断 a 中有无与 x 等值的数。 #define N 10 main() {int a[N],i,x; for(i=0;i<N;i++) scanf("%d",&a[i]); /*以下读入待查找数值*/
常用算法设计方法C语言

常用算法设计方法C语言常用算法设计方法 (1)一、迭代法 (1)二、穷举搜索法 (2)三、递推法 (6)四、递归 (7)五、回溯法 (15)六、贪婪法 (28)七、分治法 (33)八、动态规划法 (39)常用算法设计方法要使计算机能完成人们预定的工作,首先必须为如何完成预定的工作设计一个算法,然后再根据算法编写程序。
计算机程序要对问题的每个对象和处理规则给出正确详尽的描述,其中程序的数据结构和变量用来描述问题的对象,程序结构、函数和语句用来描述问题的算法。
算法数据结构是程序的两个重要方面。
算法是问题求解过程的精确描述,一个算法由有限条可完全机械地执行的、有确定结果的指令组成。
指令正确地描述了要完成的任务和它们被执行的顺序。
计算机按算法指令所描述的顺序执行算法的指令能在有限的步骤内终止,或终止于给出问题的解,或终止于指出问题对此输入数据无解。
通常求解一个问题可能会有多种算法可供选择,选择的主要标准是算法的正确性和可靠性,简单性和易理解性。
其次是算法所需要的存储空间少和执行更快等。
算法设计是一件非常困难的工作,经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等。
另外,为了更简洁的形式设计和藐视算法,在算法设计时又常常采用递归技术,用递归描述算法。
一、迭代法迭代法是用于求方程或方程组近似根的一种常用的算法设计方法。
设方程为f(x)=0,用某种数学方法导出等价的形式x=g(x),然后按以下步骤执行:选一个方程的近似根,赋给变量x0;将x0的值保存于变量x1,然后计算g(x1),并将结果存于变量x0;当x0与x1的差的绝对值还小于指定的精度要求时,重复步骤(2)的计算。
若方程有根,并且用上述方法计算出来的近似根序列收敛,则按上述方法求得的x0就认为是方程的根。
上述算法用C程序的形式表示为:【算法】迭代法求方程的根{ x0=初始近似根;d o {x1=x0;x0=g(x1);/*按特定的方程计算新的近似根*/} while ( fabs(x0-x1)>Epsilon);p rintf(“方程的近似根是%f\n”,x0);}迭代算法也常用于求方程组的根,令X=(x0,x1,…,xn-1)设方程组为:xi=gi(X) (I=0,1,…,n-1)则求方程组根的迭代算法可描述如下:【算法】迭代法求方程组的根{ for (i=0;i<n;i++)x[i]=初始近似根;do {for (i=0;i<n;i++)y[i]=x[i];for (i=0;i<n;i++)x[i]=gi(X);for (delta=0.0,i=0;i<n;i++)if (fabs(y[i]-x[i])>delta)delta=fabs(y[i]-x[i]);} while (delta>Epsilon);for (i=0;i<n;i++)printf(“变量x[%d]的近似根是%f”,I,x[i]);printf(“\n”);}具体使用迭代法求根时应注意以下两种可能发生的情况:如果方程无解,算法求出的近似根序列就不会收敛,迭代过程会变成死循环,因此在使用迭代算法前应先考察方程是否有解,并在程序中对迭代的次数给予限制;方程虽然有解,但迭代公式选择不当,或迭代的初始近似根选择不合理,也会导致迭代失败。
C语言中的算法实现

C语言中的算法实现算法是计算机科学中非常重要的概念,它是解决问题的一系列步骤或指令集。
在C语言中,我们可以使用不同的方法来实现算法。
本文将介绍一些常见的C语言算法实现方式。
一、排序算法1. 冒泡排序冒泡排序是一种简单但效率较低的排序算法。
它通过不断比较相邻的元素,并按照规则交换它们的位置,直到整个序列排序完成。
2. 选择排序选择排序是一种简单而直观的排序算法。
它每次从未排序的序列中选择最小(或最大)的元素,并将其放置在已排序序列的末尾。
3. 插入排序插入排序是一种简单且高效的排序算法。
它通过构建有序序列,对未排序的元素逐个插入到已排序的序列中,直到所有元素都被插入完成。
二、查找算法1. 顺序查找顺序查找是一种简单的查找算法。
它从列表的开头开始逐个比较元素,直到找到目标元素或查找完整个列表。
2. 二分查找二分查找是一种高效的查找算法,但要求列表必须是有序的。
它通过将待查找区域分成两部分,判断目标元素落在哪一部分,从而缩小查找范围,直到找到目标元素或确定不存在。
三、递归算法递归是一种常用的算法设计技巧。
它通过在函数内调用自身来解决相同问题的不同实例。
在C语言中,递归函数需要定义出口条件,以避免无限递归。
四、动态规划算法动态规划是一种用于解决具有重叠子问题和最优子结构性质的问题的方法。
它将问题分解为一系列子问题,并以自底向上的方式求解子问题,最终得到整体问题的解。
在C语言中,可以使用循环、数组和指针等特性来实现动态规划算法,从而有效地解决问题。
五、图算法图是一种用于描述对象之间关系的数据结构,图算法是解决图相关问题的一类算法。
常见的图算法包括深度优先搜索(DFS)和广度优先搜索(BFS)。
六、字符串算法字符串算法用于处理字符串相关的问题,如字符串匹配、编辑距离等。
C语言提供了一系列字符串处理函数,如strlen、strcpy等,可以方便地实现字符串算法。
七、数学算法C语言在数学算法方面提供了丰富的库函数支持,如求平方根、对数、指数等。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
六种常用算法一、有条不紊——递推法破解难题问:“我对数据结构有了一定了解,但还是不太懂程序。
从经典公式“程序=算法+数据结构”得知,是因为不了解算法。
能不能介绍几种简单的算法,当然从最容易懂的那种开始了?”答:“算法就是能够证明正确的解题步骤,算法有许多种,最简单的无非下面的六种:递推法、贪心法、列举法、递归法、分治法和模拟法。
刚听名字挺吓人的,其实有好多程序我们平常都见过。
这些算法当中,最最简单的莫过于递推算法了。
下面举例说明。
”1、什么是递推法递推法这种解题方法其实在我们编程的过程中用的很多,只不过没有将其上升到理论的高度罢了。
所谓递推法,就是找出和时间先后相联系或和数的大小相联系的步骤,上一步和下一步和数字的增大或减小有一定的联系。
我们要么从前向后(或从小到大)推导,也可从后向前(或从大到小)推导。
由此得出两种推导方法:顺推法和倒推法。
请看下面的示例。
示例:猴子分食桃子:五只猴子采得一堆桃子,猴子彼此约定隔天早起后再分食。
不过,就在半夜里,一只猴子偷偷起来,把桃子均分成五堆后,发现还多一个,它吃掉这桃子,并拿走了其中一堆。
第二只猴子醒来,又把桃子均分成五堆后,还是多了一个,它也吃掉这个桃子,并拿走了其中一堆。
第三只,第四只,第五只猴子都依次如此分食桃子。
那么桃子数最少应该有几个呢?编程简析:怎样编程呢?先要找一下第N只猴子和其面前桃子数的关系。
如果从第1只开始往第5只找,不好找,但如果思路一变,从第N到第1去,可得出下面的推导式:第N只猴第N只猴前桃子数目5 s5=x4 s4=s5*5/4+13 s3=s4*5/4+12 s2=s3*5/4+11 s1=s2*5/4+1s1即为所求。
上面的规律中只要将s1-s5的下标去掉:s=xs=s*5/4+1s=s*5/4+1s=s*5/4+1s=s*5/4+1所以可以用循环语句加以解决。
综观程序的整体结构,最外是一个循环,因为循环次数不定,可以使用While循环,其结束条件则是找到第一个符合条件的数。
为了做出上面while循环的结束条件,还需进一步分析上述规律的特点,要符合题目中的要求,s1-s4四个数必须全部为整数,这个可作为条件。
具体实现请参看源程序。
int peach(){ //最少最后应该是5 的倍数加1但同时又是4 的倍数, 从16 起加int k = 0,s = 0, x = 16,i = 0;while( k< 4){k = 0;s = x;for(i=4; i>=1; i--){if((s == (s/4)*4) && (s == ((s/5)*5 + 1))) //C 的整除判断{// 计一次数k++;printf("value s:%d k:%d i:%d\n", s, k, i);}s = (s/4)*5 + 1;}x += 5;}return s;}二、稳扎稳打——贪心法破解难题问:“算法除了递推法,该轮到贪心法了吧,从字面上理解,这种方法有些贪得无厌还是…?”答:“基本算法中的递推法是我们最常使用的,贪心法是另一种有意思的算法。
贪心法不仅仅是贪婪,而且是每一步都贪婪!下面举例说明。
”1、什么是贪心法贪心法就是做一种目前最贪婪的行动,一步步解决问题。
贪心法和递推法有相似之外,也是从问题的某一个初始解出发,向给定的目标递推,但不同的是每一步不是依据某一个固定的递推式,而是做一个当时看似最佳的贪心选择,不断地将问题归结为更小的相似的问题。
示例:删数问题链盘输入一个高精度的数N,去掉任意S个数字后剩下的数字按原左右次序组成一个新的正整数,编程对于给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。
为了便于操作,将N做为字符串的形式输入,可以使用尽可能逼近目标的贪心算法来完成,删数的过程中是一个一个进行删除的,为了保证最后得到的数最小,每一步总是要删除使剩下的数最小的数字。
之所以做出这样贪心的选择,是因为删S个数字的最优解,包含了删除一个数字的子问题的最优解。
为了实现上述目的,我们可以进行S次选择,每次都选择N中最大的数字,此数字选择后将不再参与下次的选择。
2、小结:这就是有趣的贪心算法,说是贪得无厌可以,说是守住当前的既得利益,以此为基础,再稳扎稳打地进行下一步也行!三、滴水不漏——列举法破解难题问:“列举法是种什么样子的算法呢?”答:“列举法是比贪心法还要贪得多的算法,列举法也是一种比较笨但却很有效的算法,他想要的东东,一种情况他都不想落下,大有宁可错杀一千,不可放过一个的阵势。
下面举例说明。
”1、什么是列举法列举是针对问题所有的可能一一查看是不是符合条件,有些“宁肯错杀一千,不可放过一个”的作风。
下面的老题最能说明这种情况。
示例:百钱买百鸡:公鸡3元每只,母鸡5元每只,小鸡1元3只,一百元钱买一百只鸡。
请求出公鸡,母鸡和小鸡的数目。
编程简析我们做最极端的假设,公鸡可能是0-100,母鸡也可能是0-100,小鸡还可能是0-100,将这三种情况用循环套起来,那就是1000000种情况。
这就是列举法。
为了将题目再简化一下,我们还可以对上述题目进行一下优化处理:假设公鸡数为x,母鸡数为y,则小鸡数是100-x-y,也就有了下面的方程式:3*x+5*y+(100-x-y)/3=100从这个方程式中,我们不难看出大体的情况:公鸡最多有33只,最少是没有,即x的范围是0-33;母鸡最多20只,最少0只,即母鸡的范围是0-20;有了公鸡母鸡,小鸡数自然就是100-x-y只。
可能的方案一共有34*21种,在这么多的方案中,可能有一种或几种正好符合相等的条件。
电脑怎样工作呢?计算机事实上就是将上述34*21种方案全部过滤一遍,找出符合百钱买百鸡条件的(也即上式),只要符合,这就是我们要的输出结果。
程序实现:我们怎样将这34*21种方案罗列出呢?这么多的方案,最好的办法是还是用循环。
可用循环和循环的嵌套,一个关于公鸡数和一个关于母鸡数的循环套起来,就能将所有的方案都遍历。
后面的问题成了怎样判断哪一个方案是我们寻找的符合条件和方案呢?只能根据百钱买百鸡了,即3*x+5*y+(100-x-y)/3=100作为条件,在条件成立的一方输出x,y,和100-x-y的值就行了,这是分支要解决的问题,程序的整体结构有了,两个嵌套循环中套分支。
2、小结这就是列举法,将可能的情况一网打尽;不过在应用过程中,我们最好还是做些优化,不然,要浪费好多没必要浪费的时间。
四、镜里照镜——递归法破解难题问:“前几种办法的确名如其法,比较笨。
有没有比较潇洒一点的算法?递归属不属于些类算法呀?”答:“递归一种非常奇妙和美妙的算法形式,奇妙美妙的背后是比较难理解。
但用起来却异常简洁。
”1、什么是递归说白了递归就象我们讲的那个故事:山上有座庙,庙里有个老和尚,老和尚在讲故事,它讲的故事是:山上有座庙,庙里有个老和尚,老和尚在讲故事,它讲的故事是:……也就是直接或间接地调用了其自身。
就象上面的故事那样,故事中包含了故事本身。
因为对自身进行调用,所以需对程序段进行包装,也就出现了函数。
函数的利用是对数学上函数定义的推广,函数的正确运用有利于简化程序,也能使某些问题得到迅速实现。
对于代码中功能性较强的、重复执行的或经常要用到的部分,将其功能加以集成,通过一个名称和相应的参数来完成,这就是函数或子程序,使用时只需对其名字进行简单调用就能来完成特定功能。
函数又可分为自定义的和系统附带的,但不管是自定义的还是系统的,他们都对相应的功能进行了封装,以利于我们经常性地使用。
例如我们的对一个小数取整数INT()函数,不论什么样的小数,往()中一放,将来得到的值就自动将小数去除了。
函数执行完将返回一个值,当然这个值可以是各种类型的,子程序仅仅执行一个过程,不返回数值。
函数和子程序是执行递归的干将。
示例:小猴吃枣:小猴第一天摘下若干枣子,当即吃掉了一半,不过瘾又多吃了一个;第二天吃了剩下的一半又多吃了一个;以后每一天都吃了前一天剩下的一半多一个。
到第十天小猴再想吃时,见到只剩下一只枣子了。
问第一天这堆枣子有多少?从上题中我们可看到一个令人欣喜的规律,第十天为1,第一到第九天中后一天与1的和的两倍与前一天相等。
2、小结函数和子程序是程序瘦身计划的一部分,通过它们可以使程序中的代码适当减肥,长度维持在一个更合理的位置。
这种作用和循环的瘦身作用一起,使一个执行很长的代码可以变得很简洁。
这也更适合我们利用计算机作为工具的目的:人类做尽量少的工作,计算机仍能解决原先的问题。
另一个奇妙之处是:他们创造了递归!五、各个击破——分治法破解难题问:“问题不能一下子解决,难道不能分开解决吗,有没有算法能实现各个击破以求解决问题呢?”答:“可以的,通过各个击破的方法解决问题的算法叫做分治法。
下面我们通过示例来看一下。
”1、什么是分治法为了解决一个问题,算法有时需不止一次地对自身进行调用,来解决相类似的子问题。
这样的算法通常称为分治法:将原问题分成n个规模较小而结构与原问题相似的子问题。
下面通过排序的一种方法来看一下。
希尔排序即是采用分治法来进行排序的,又称做缩小增量排序,其思想是:把已经在数组中的数据按下标的一定增量分组,对分出的每一小组使用插入排序,随着增量逐渐减小,所分成的组包含的数据越来越多,直到减小到1时,整个数据合并成一组,构成一组有序数,则完成排序。
示例:十个数,从大到小排序。
数据放在一个数组a(10)中,假如原始数据如下:70. 53. 57. 28. 30. 77. 1. 76. 81. 70,则排序过程如下:增量值5: 77. 53. 76. 81. 70. 70. 1. 57. 28. 30.2: 77. 81. 76. 70. 70. 57. 28. 53. 1. 30.1: 81. 77. 76. 70. 70. 57. 53. 30. 28. 1.其中上面三个增量值对应的都是以该增量完成本轮排序后的情况,看增量为5时要和原始数据比较,增量为2的情况要和5比较,1要和2比较,这样其中的规律就清楚了。
2、小结在进行希尔排序时,需注意增量序列的取值方法,并且使这些序列中的值没有除1之外的公因子,且最后一个增量值必须为1。
能解决问题的办法都是好办法,问题不一定整体解决才好。
这就是分治的思想。
六、乱打误撞——模拟法破解难题问:“电脑解决确定问题可做到手到擒来,对于电脑中实现一个不确定的问题,例如彩票或抽奖,怎样做呢?”答:“算法的美妙在于其准确和确定,而另有一种价值则在于其不确定,象我们的抽奖程序和彩票程序。
确定的问题电脑可以处理,不确定的问题电脑也能处理,随机函数就是实现电脑中不确定事件的重要砝码。
下面我们通过示例来看一下。