elsep=m+1;
}
if(p>q)return(-1);
}
4.穷举(***)
穷举法的基本思想是:
一一列举各种可能的情况,并判断哪一种可能是符合要求的解。
这是一种在“没有其它办法的情况的方法”,是一种最“笨”的方法,然而对一些无法用解析法求解的问题往往能奏效,通常采用循环来处理穷举问题。
【例题】有1、2、3、4四个数字,能组成多少个互不相同且无重复数字的三位数?
都是多少?
程序分析:
可填在百位、十位、个位的数字都是1、2、3、4。
组成所有的排列后再去掉不满足条件的排列。
main()
{inti,j,k;
for(i=1;i<5;i++) /*以下为三重循环*/
for(j=1;j<5;j++)
for(k=1;k<5;k++)
if(i!
=k&&i!
=j&&j!
=k) /*确保i、j、k三位互不相同*/
printf("%d,%d,%d\n",i,j,k);
}
数值计算常用经典算法
级数计算(递推法)(*****)
累加(*****)
使用循环时,要注意根据问题确定循环变量的初值、终值或结束条件,更要注意用来表示最后结果的初值。
用c语言实现1+2+3+4+5+……+n的累加。
【方法1】for循环实现
intadd(intn)
{inti,sum=0;
for(i=1;i<=n;i++)sum=sum+i;
returnsum;
}
【方法2】while循环实现
intadd(intn)
{inti,sum;
sum=0;i=1;
while(i<=n)
{sum=sum+i;
i=i+1;
}
returnsum;
}
do-while循环也可以实现累加。
累乘
在累乘之前,一定要将用于存放乘积的变量的值初始化为1。
用c语言求n的阶乘:
n!
=1234…n(n>=0)
intproduct(intn)
{inti,p=1;
for(i=2;i<=n;i++)p=p*i;
returnp;
}
如果n的值比较大,考虑累乘的结果可能会超过32767,函数返回值应定义为长整型,确保程序运行的正确。
longfunc(intn)
{inti;
longp=1;
for(i=2;i<=n;i++)p*=i;
returnp;
}
用递推法求n!
的程序段如下:
for(fac=1,i=2;i<=n;i++)fac=fac*i;
【例题】有一分数序列:
求出这个数列的前20项之和。
本题主要要抓住分子与分母的变化规律。
main()
{intn,t,number=20;
floata=2,b=1,s=0;/*a表示分子,b表示分母*/
for(n=1;n<=number;n++)
{ s=s+a/b;
t=a;
a=a+b;
b=t;
}
printf("sumis%9.6f\n",s);
}
【例题】求1+2!
+3!
+...+20!
的和
main()
{floatn,s=0,t=1;
for(n=1;n<=20;n++)
{ t*=n;
s+=t;
}
printf("1+2!
+3!
...+20!
=%e\n",s);
}
运行结果为:
1+2!
+3!
...+20!
=2.561327e+18
本题将变量定义为float,因为long型数据的范围为-21亿~21亿。
无法容纳求得的结果。
int型的就更不用说了,表示范围只有-32768~32767。
【例题】以下程序的功能是:
根据公式和精度计算π的近似值。
#include
#include
doublePI(doubleeps)
{doubles=0,t=1.0;intn;
for(n=1;___________;n++)
{s+=t;t=t*(n-1)/(2*n-1)?
?
__________;}
return2.0*s;
}
voidmain()
{doublee=1e-6;
/*e是计算精度要求,这里表示允许运算结果值在小数点后第6位有误差*/
printf("%f",_________________);
}
【例题】以下程序通过给出的公式计算π的近似值,计算过程在所加项的值小于10-6时终止。
#include
main()
{doublesum=0.5,t,t1,t2,t3;
intodd=1,even=2;
t=t1=t2=1.0;t3=0.5;
while(t>1e-10)
{t1=____t1*odd/even?
?
_____;
odd+=2;even+=2;
t2=1.0/odd;
t3=___t3*0.5*0.5?
?
________;
t=t1*t2*t3;
sum+=t;
}
printf("\nPI=%.8lf",________sum_____;
}
解决各类问题的一般算法
数组问题
1.求最大、最小值(*****)
1)查找一维数组a[]中的最大值,n为数组的大小
intfunmax(inta[],intn)
{inti,max=a[0];
for(i=1;iif(max>a[i])max=a[i];
returnmax;
}
2)查找二维数组a中的最小值
有一个3×4的矩阵,求所有元素的最小值。
二维数组作函数的参数,第一维的长度可以缺省,第二维的长度不能缺省。
intfunmin(inta[][4])
{inti,j,min;
min=a[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(a[i][j]returnmin;
}
2.求和及平均值(*****)
求数组的平均值,先用循环将数组的所有元素相加,最后返回所得的和除以数组元素的个数。
intaverage(inta[],intn)
{inti,avg=0;
for(i=0;i/*若avg的初值为a[0],则i从1开始*/
returnavg/n;
}
若求数组的和,则return语句改为returnavg。
若所求的数组的平均值不是从第一个元素开始的,不管从那个元素开始,只要将开始元素的地址作为实际参数即可。
例如,数组a共有20个元素,求最后5个元素的平均值的调用方式为:
average(&a[15],5);
3.计数(*****)
求满足要求的数的个数。
一般在循环中对每一个元素都用if语句进行判断,满足条件的话,计数的变量增1。
例如:
对数组中的n个学生成绩,求不及格人数的个数。
intcount(inta[],intn)
{intc=0;
for(i=0;iif(a[i]<60)c++;
returnc;
}
4.数组元素逆置(*****)
算法思想:
将数组元素的第一个与最后一个元素交换位置,第二个元素与倒数第二个元素交换位置……。
需要注意的是,只能遍历数组的一半元素,如果遍历整个数组,每个元素都做了两次交换,最终又回到原来的位置上。
exchange(inta[],intn)
{inti,t;
for(i=0;i{t=a[i];a[i]=a[n-i-1];a[n-i-1]=t;}
}
5.在数组中插入一个数
1)在数组的指定位置插入一个数
如果在a[i]后插入一个x,从最后一个元素开始,将a[i+1]以后的元素往后移,空出位置后将x放在a[i+1]位置处。
for(j=N-1;j>i;j--)a[j+1]=a[j];/*移位*/
a[i+1]=x;/*插入x*/
2)在已排序的数组中插入一个数
有一个已经排好序的数组,现有一个数x,要求按原来的规律将它插入数组中。
首先判断此数是否大于最后一个数,然后再考虑插入中间的情况,找插入点,先将插入点之后的数,依次后移一个位置。
#defineN6
voidinsert(inta[N],intnum)
{inti,j;
if(num>a[N-2])a[N-1]=num;/*插在最后*/
else
for(i=0;iif(a[i]>num)/*找插入点,插在a[i]位置*/
{for(j=N-2;j>=i;j--)a[j+1]=a[j];
/*将a[i]以后的元素从最后一个元素开始后移*/
a[i]=num;/*将num放在a[i]处*/
break;
}
}
6.删除数组中的一个元素a[i]
删除数组中的元素a[i],就是将a[i]以后的元素往前移一个位置。
voiddel(inta[],intn,inti)
{intj;
for(j=i;j}
整数问题
1.素数问题
素数是指除1和本身外不能被其他任何整数整除的正整数。
1)判断m是否是素数的函数
#include
intprime(intm)
{inti,k;
k=sqrt(m);/*k是不大于m的平方根的最大整数*/
for(i=2;i<=k;i++)
if(m%i==0)return0;/*不是素数,返回0*/
return1;
}
2)把m~n范围内的素数依次放入数组a中,返回素数个数。
#include
intprime(inta[N],intm,intn)
{inti,k,j;
j=0;/*j为素数的个数*/
for(i=m;i<=n;i++)
{for(k=2;k<=sqrt(i);k++)
if(i%k==0)break;/*i不是素数,内循环结束*/
if(k>sqrt(i))a[j++]=i;/*i为素数,存入数组*/
}
returnj;
}
2.求最大公约数和最小公倍数
1)求最大公约数(欧几里得算法)
最大公约数的算法也叫欧几里得算法,采用的是辗转相除法求两数m、n最大公约数,其算法步骤如下:
1对于已知两数m和n,;
2将m除以n得余数r;
3若r为0,则n为求得的最大公约数,算法结束,否则执行下一步;
4n赋给m,r赋给n,再重复执行上面的两步。
算法结束时,m中所存放的值即为最大公约数。
gcd(intm,intn)
{intt,r;
if(mwhile(n)
{r=m%n;/*求余*/
m=n;n=r;/*窜位,准备下次求余*/
}
returnm;
}
2)求最小公倍数
算法:
两数之积除以最大公约数所得的值即为最小公倍数
gcd(intm,intn)
{intt,r,p;
p=m*n;
while(n)
{r=m%n;m=n;n=r;}
returnp/m;
}
如果在同一个程序中,可以直接调用最大公约数的函数。
gcd(intm,intn)
{intt,r;
p=m*n;
returnp/gcd(m,n);
}
3.整数拆分与拼接
1)拆整数
求一个整数的位数及将各位数字放在数组中,返回整数的位数。
intpdigit(longn,inta[])
{inti=0,k;
while(n)
{a[i++]=n%10;/*取余数*/
n=n/10;/*求整数,去掉余数后的数*/
}
return(i);
}
下面的函数是求整数n的各位数字之和。
intsum(intn)
{ints=0;
while(n)
{s=s+n%10;n=n/10;}
return(s);
}
若求各位数字之积,只要将s的初值“0”改为“1”,“加”改成“乘”即可。
2)拼整数
在键盘输入若干个数字,直到输入负数为止,输出这些数字组成的数,先输入的数字作为最高位。
main()
{longnum=0;
intn;
scanf("%d",&n);
while(n>=0)
{num=num*10+n;
scanf("%d",&n);
}
printf("%ld",num);
}
4.求反序数和回文数
1)求反序数
将一个数的数字排列顺序完全颠倒过来,就变成另一个数,这个数就是该数的反序数,如123的反序数为321。
intinte(intn)
{intnum=0;
while(n)
num=num*10+n%10;
n=n/10;
{
}
return(num);
}
2)求回文数
一个数与它的反序数相等,这样的数称为回文数。
例如12321,6336等就是回文数。
判断一个数是否是回文数,先求出它的反序数,再判断两者是否相等。
①判断n是否是回文数的函数
intpalin(intn)
{ints=0;
m=n;
反序数
while(m)
{s=s*10+m%10;
m=m/10;
}
if(s==n)return
(1);
elsereturn(0);
}
②求指定范围内的回文数
写一个函数,求指定范围内(m1~m2之间)的回文数,保存到指定的数组中,并返回回文数的个数。
intpalin(longm1,longm2,longx[])
{longi,n,s;/*s是i的回文数*/
intk=0;/*k回文数个数,数组下标*/
for(i=m1;i<=m2;i++)
{n=i;s=0;
while(n)/*求反序数*/
{s=s*10+n%10;
n=n/10;
}
if(i==s){x[k]=i;k++;}/*若是回文数,放入数组a中*/
}
returnk;/*返回回文数的个数*/
}
5.因子、完全数、互满数对
1)求a的因子并存放在数组中
因子是指能被a整除的数,包含1和该数本身,真因子包含1不包含本身。
intfun(inta,intx[N])
{inti,j=0;
for(i=1;i<=a;i++)
if(a%i==0)x[j++]=i;
returnj;/*返回因子的个数*/
}
2)找指定范围内的完全数
完全数是指一个正整数的所有真因子之和等于本身的数,因子包含1但不包含本身,例如:
:
6=1+2+3,28=1+2+4+7+14,所以6和28是完全数。
intfun(inta[N],intm,intn)
{inti,j,s;
intk=0;
for(i=m;i<=n;i++)
{s=0;for(j=1;j
if(i%j==0)s=s+j;
if(i==s)a[k++]=i;
}
returnk;
}
3)互满数对(亲密数对)
互满数对是指两个数中,其中的一个数的真因子之和都等于另一个数。
即a的真因子之和为b,b的真因子之和为a。
如:
220与184,1184与1210就是互满数对。
intfun(ints[][2],intm1,intm2)
{ints1,s2,count,a,i,j;
count=0;
for(a=m1;a<=m2;a++)
{s1=1;s2=1;
for(i=2;ifor(j=2;jif((s2==a)&&(a{s[count][0]=a;
s[count][1]=s1;
count++;
}
}
returncount;
}
6.求满足条件的数或数对
本类型的题目是近年考得比较多的类型,其变化也比较多,需要分析,灵活运用。
比较简单的如同构数,还有典型的Armstrong数。
实际上,素数、回文数、完全数等都是属于满足要求的数。
很多问题都是由基本的算法变化来的。
1)同构数
同构数是其值等于其右边数字平方数的整数。
如25,36都是同构数(25=52,36=62)。
下面的程序是求1~99之间的所有同构数。
main()
{inti,k;
for(i=1;i<100;i++)
{k=i%10;/*求未位数*/
if(k*k==i)printf(“%d,“,i);/*输出满足要求的数*/
}
2)Armstrong数
一个n位的正整数,其各位数的n次方之和等于这个数,称这个数为Armstrong数。
例如,153=13+53+33。
1634=14+64+34+44。
下面的程序求所有三位和四位数的Armstrong