辗转相除法
作用:
这种算法是一种朴素的,求两个数的最大公约数的算法。
流程:
1.输入两个数:a,b。
2.定义一个新的数r。
3.将a对b取模的值给予r,然后将b的值给予a,将r的值给予b。
4.判断b的值是否等于零,如果结果是真,执行第5步。如果结果是假,回到第3步继续执行。
5.输出a的值(此时a的值就是a和b的最大公约数)。
代码示例:
#include <stdio.h>
#include <stdlib.h>
/*
算法:辗转相除法
用于求得两个数的最大公约数
*/
int main()
{
int a,b;
scanf("%d%d",&a,&b);
while(b!=0)
{
int r;
r=a%b;
a=b;
b=r;
}
printf("%d",a);
return 0;
}
注:如要求最小公倍数,只需用一开始输入的a除去最大公约数。然后再将得到的结果乘上b即可。
迭代
作用:
这是一种编程的思想,在特定的条件下,可以大大的降低程序的计算量,从而大幅度提高运算效率。
流程:
简单的来说,就是当需要循环运算某个公式时,通过合理的利用上个循环计算的结果,省去重复计算的部分来提高程序效率。
代码示例:
例如:需要求1!+2!+3!+...+20!这样的数学算式的结果
解法一:
int main()
{
//一:
int i=1,j=1,sum1=0;
double t=1;
for(;i<=12;i++)
{
t=1;
for(j=1;j<=i;j++)
{
t*=j;
}
sum1+=t;
}
printf("sum1--->%d\n",sum1);
return 0;
}
解法二:
int main()
{
//一:
int i1=1,sum1=0,t1=1;
while(i1<=5)
{
t1*=i1;//test1中的解法每次都要从1开始累乘,而这里直接用上次的结果乘,省下了无数循环,效率上是一个飞跃。
sum1+=t1;
i1++;//对于while循环,结尾的变量累加一点要记得写!
}
printf("sum1--->%d\n",sum1);
return 0;
}
解析:
1.解法一使用的是最简单的解法,外循环负责i的值从1到20。内循环负责计算i!的值。
2.观察解法一和解法二,我们发现:解法一1到20的每个值的阶乘都从1开始循环累加计算(即:当需要3的阶乘时,计算过程为3!=1*2*3,而当需要4的阶乘时,计算过程为4!=1*2*3*4)。而解法二则保存了上个元素阶乘的值,并在需要下个元素阶乘的值时调用保存的值以省略重复的计算过程(即:当需要3的阶乘时,计算过程为3!为3!=2!*3,当需要4的阶乘时,计算过程为4!为4!=3!*4)。
3.解法二即是利用了迭代的方法改进的程序,在运算这个例子时,二与一相比,在计算2!的值时减少了一个循环的计算量,在计算3!时减少了两个循环的计算量。以此类推,如果要计算的是1!+2!+3!+...+1000!的话,使用迭代优化后的程序能节省的计算资源是十分可观的。
进阶:
通过合理的使用迭代可以节省大量的计算资源。但显然并不是所有程序都能够使用迭代的。也并不是所有问题使用迭代解决都能收获奇效的。
对于适合使用迭代的问题,以及这样的问题该如何使用迭代,给出如下示例:
对于:S = 1-(x^2)/(2!)+(x^4)/(4!)-(x^6)/(6!)+...+((-1)^n)*((x^(2*n))/(2*n)!)
这个公式,要求输入一个x和n,然后输出S的值
乍一看是一个十分复杂的东西,但其实这个可以看成高中数学中的数列来看:
上述公式的最后一个值((-1)^n)*((x^(2*n))/(2*n)!)即是这个数列的通项公式。
当希望用迭代解决这个问题时,需要明确迭代的作用机制:利用上一次计算的值来代替重复的循环计算。
对于数列来说,可以利用他的递推公式来实现这一过程:
通过保存f(n-1)的值,
将复杂的
f(n)=((-1)^n)*((x^(2*n))/(2*n)!);
简化为
f(n)=k*f(n-1)+b;//或其他形式,这里只是举个例子。
以节省计算量。
通过f(n)/f(n-1)等一系列运算,得到该数列的递推公式:f(n)=-((x*x)/(2*n*(2*n-1)))*f(n-1)
代码示例:
#include <stdio.h>
#include <stdlib.h>
/*
对于:S = 1-(x^2)/(2!)+(x^4)/(4!)-(x^6)/(6!)+...+((-1)^n)*((x^(2*n))/(2*n)!)
这个公式,要求输入一个x和n输出S的值
*/
int main()
{
double x,n;
double s=0;
scanf("%lf%lf",&x,&n);
int i=1;
double f2=0,f1=1;
s+=f1;
while(i<=n)//循环n次
{
f2=f1*(-((x*x)/(2*i*(2*i-1))));//同过通项公式得出的递推公式
s+=f2;
f1=f2;
f2=0;
i++;
}
printf("%f",s);
return 0;
}
结果:
解析:
如图,这个程序输出结果十分快速,就是因为用迭代优化了运算过程。
巴什博弈
作用:
解决一种取物问题
解析(来自百度):
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。
代码示例:
#include <stdio.h>
#include <stdlib.h>
/*
取石子(一)
时间限制:3000 ms | 内存限制:65535 KB
难度:2
描述
一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子。游戏的规则是这样的。设有一堆石子,数量为N(1<=N<=1000000),两个人轮番取出其中的若干个,每次最多取M个(1<=M<=1000000),最先把石子取完者胜利。我们知道,TT和他/她的室友都十分的聪明,那么如果是TT先取,他/她会取得游戏的胜利么?
输入
第一行是一个正整数n表示有n组测试数据
输入有不到1000组数据,每组数据一行,有两个数N和M,之间用空格分隔。
输出
对于每组数据,输出一行。如果先取的TT可以赢得游戏,则输出“Win”,否则输出“Lose”(引号不用输出)
样例输入
2
1000 1
1 100
样例输出
Lose
Win
*/
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int N,M;
scanf("%d%d",&N,&M);
if(N%(M+1)==0)
{
printf("Lose\n");
}
else
{
printf("Win\n");
}
}
return 0;
}
结果: