学习笔记---几种基本的算法于几种优化程序的方法

41 篇文章 0 订阅
16 篇文章 0 订阅

辗转相除法


作用:

这种算法是一种朴素的,求两个数的最大公约数的算法。


流程:

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;
}

结果:








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值