基本算法思想

常用算法思想概述

  在实际应用中,不同的问题往往解题的思路不同。如果找不到一个合适的思路,那么可能使求解决过程变得复杂,更有甚者无法求解得到结果。选择合理的思路,往往可以帮助用户理清问题的头绪,更快地解决问题。算法就是起到了这个作用。
  根据问题的不同,我们可以采用如下几种常用的算法来进行求解。

  • 穷举算法思想
  • 递推算法思想
  • 递归算法思想
  • 分治算法思想
  • 概率算法思想

穷举算法思想

  穷举算法(Exhaustive Attack method)是最简单的一种算法,其依赖于计算机的强大计算能力,来穷尽每一种可能的情况,从而达到求解问题的目的。穷举算法效率并不高,但是适合于一些没有明显规律可循的场合。

基本思想

  穷举算法的基本思想就是从所有可能的情况中搜索正确的答案,其执行步骤如下:
  (1)对于一种可能的情况,计算其结果。
  (2)判断结果是否满足要求,如果不满足则继续执行(1)步来搜索下一个可能的情况;如果满足要求,则表示寻找到一个正确的答案。
  在使用穷举算法时,需要明确问题的答案的范围,这样才可以在指定范围内搜索答案,指定范围之后,就可以使用循环语句和条件判断语句逐步验证候选答案的正确性,从而得到需要的正确答案。

实例

  今有鸡兔同笼,上有三十五头,下有九十四足,问鸡兔各几何?
  这个问题的大致意思是:在一个笼子关着若干只鸡和若干只兔,从上面数共有35个头,从下面数共有94只脚,问笼中鸡和兔的数量各是多少?

java

public static void main(String[] args) {

        int head, foot;
        Scanner sc = new Scanner(System.in);
        System.out.println("穷举法求解鸡兔同笼问题");
        System.out.print("请输入头数: ");
        head = sc.nextInt();
        System.out.print("请输入脚数: ");
        foot = sc.nextInt();
        qiongju(head, foot);
    }

    private static void qiongju(int head, int foot) {
        int haveResult = 0;
        int chick, habbit = 0;
        for(chick = 0; chick <= head; chick++){
            habbit = head - chick; //鸭数目
            if(chick * 2 + habbit * 4 == foot){
                haveResult = 1; //判断,确定是否有答案
                break;
            }
        }
        if(haveResult == 1)
            System.out.println("鸡有" + chick + "只, 兔有" + habbit + "只");
        else
            System.out.println("无法求解!");
    }

运行结果

穷举法求解鸡兔同笼问题
请输入头数: 35
请输入脚数: 94
鸡有23只, 兔有12只

递推算法思想

  递推算法是很常用的算法思想,在数学计算等场合有着广泛的应用,递推算法适合有着明显公式规律的场合。

递推算法基本思想

  递推算法是一种理性思维模式的代表,其根据已有的数据和关系,逐步推导而得到结果。递推算法的执行过程如下:
  (1)根据已知结果和关系,求解中间结果。
  (2)判定是否达到要求,如果没有达到,则继续根据已知结果和关系求解中间结果;如果满足要求,则表示寻找到一个正确的答案。
递推算法往往需要用户知道答案和问题之间的逻辑关系。在许多数学问题中,都有着明确的计算公式可以遵循,因此往往可以采用递推算法来实现。

实例

  数学里面的斐波那契数列便是一个使用递推算法的经典例子。13世纪意大利数学家斐波那契的《算盘书》中记载了典型的兔子产仔问题,其大意如下:
  如果一对两个月大的兔子以后每一个月都可以生一对小兔子,而一对新生的兔子出生两个月后才可以生小兔子。也就是说,1月份出生,3月份才可产仔。那么假定一年内没有产生兔子死亡事件,那么1年后共有多少对兔子呢?

  分析,我们来逐月看一次每月的兔子对数:
第一个月:1对兔子;
第二个月:1对兔子;
第三个月:2对兔子;
第四个月:3对兔子;
第五个月:5对兔子;
……
  从上面可以看出,从第3个月开始,每个月的兔子总对数等于前两个月兔子数的总和。相应的计算公式如下:第n个月兔子总数Fn=Fn-2 + Fn-1

java

public static void main(String[] args) {
        int month, num; //月份数
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入繁殖时间(月):");
        month = sc.nextInt();
        num = Fabonacci(month); //斐波那契,求解
        System.out.printf("经过%d月的时间,共能繁殖成%d对兔子", month, num);
    }

    private static int Fabonacci(int month) { //递归调用 
        int t1, t2;
        if(month == 1 || month ==2) return 1;
        else{
            t1 = Fabonacci(month - 2);
            t2 = Fabonacci(month - 1);
            return t1 + t2;
        }
    }

运行结果:

请输入繁殖时间(月):12
经过12月的时间,共能繁殖成144对兔子

递归算法思想

  递归算法是很常用的算法思想,使用递归算法,往往可以简化代码编写,提高程序的可读性,但是,有的不合适的递归往往导致程序的执行效率变低。

递归算法基本思想

  递归算法就是在程序中不断反复调用自身来达到求解问题的方法。这里的重点是调用自身,这就要求待求解的问题能够分解为相同问题的一个子问题。这样,通过多次递归调用,便可以完成求解。
  递归调用是一个方法在其方法体内调用其自身的方法调用方式。这种方法也称为“递归方法”。在递归方法中,主调方法又是被调方法。执行递归方法将反复调用其自身。每调用一次就进入新的一层。
  方法的递归调用分两种情况:直接递归和间接递归。

  • 直接递归,即在方法中调用方法本身。
  • 间接递归,即间接地调用一个方法,如func_a调用func_b,func_b调用func_a,间接递归用得不多。
      编写递归方法时,必须使用if语句强制方法在未执行递归调用前返回。如果不这样做,在调用方法后,它将永远不会返回,这是一个很容易犯的错误。

实例

  求n的阶乘:n! = n * (n-1) * (n-2) * ……* 2 * 1

java

public static void main(String[] args) {
        int n;
        long result; 
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入要求阶乘的一个整数:");
        n = sc.nextInt();
        result = Fact(n); //阶乘方法,求解
        System.out.printf("%d的阶乘结果为%s", n, result);
    }

    private static long Fact(int n) {
        if( n <= 1) return 1;
        else return n * Fact(n-1);
    }

分治算法思想

  分治算法是一种化繁为简的算法思想。分治算法往往应用于计算步骤比较复杂的问题,通过将问题简化而逐步得到结果。

分治算法基本思想

  分治算法的基本思想是将一个计算复杂的问题分为规模较小,计算简单的小问题求解,然后综合各个小问题,而得到最终问题的答案,分治算法的执行过程如下:
  (1)对于一个规模为N的问题,若该问题可以容易地解决(比如说规模N较小),则直接解决;否则执行下面的步骤。
  (2)将该分解为M个规模较小的子问题,这些子问题互相独立,并且与原问题形式相同。
  (3)递归地解这些子问题
  (4)然后,将各子问题的解合并得到原问题的解。

实例

  通过一个例子来看分治算法的应用。一个袋子里有30个硬币,其中一枚是假币,并且假币和真币一模一样,肉眼很难分辨,目前只知道假币比真币重量轻一点,请问如何区分出假币呢?
1. 分治算法
  我们先来分析一下寻找假币问题,可以采用递归分治的思想来求解这个问题,操作步骤如下:
  (1)首先为每个银币编号,然后可以将所有的银币等分为两份,放在天平的两边。这样就将区分30个硬币的问题,变为区别两堆硬币的问题。
  (2)因为假银币的分量较轻,因此天平较轻的一侧中一定包含假银币。
  (3)再将较轻的一侧中的硬银币等分为两份,重复上述的做法。
  (4)直到剩下两枚硬银币,可用天平直接找出假币来。

java

public static void main(String[] args) {
        final int MAXNUM = 30; //银币总数
        int[] coin = new int[MAXNUM]; //银币数组
        initialization(coin); //数组初始化,设置其中一枚为假的
        int index = FalseCoin(coin, 0, coin.length - 1); //分治求解
        System.out.printf("在%d枚银币中,第%d枚是假的", coin.length, index);
    }

    //分治求解
    private static int FalseCoin(int[] coin, int low, int high) {
        int sum1, sum2;//sum1是前半段和,sum2是后半段和
        int index; //假币位置
        sum1 = sum2 = 0;
        if(low + 1 == high) //剩两枚
        {
            if(coin[low] < coin[high]) return low + 1;
            else return high + 1;
        }
        if((high - low + 1) % 2 == 0){ //剩偶数枚银币

            for(int k = low; k <= low + (high - low)/2; k++) //前半段和
                sum1 = sum1 + coin[k];
            for(int k = low + (high - low)/2 + 1; k <= high; k++) //后半段和
                sum2 = sum2 + coin[k];
            if(sum1 > sum2) return FalseCoin(coin, low + (high - low)/2 + 1, high);
            else return FalseCoin(coin, low, low + (high - low)/2);

        }else{  //剩奇数枚银币

            for(int k = low; k <= low + (high - low)/2 - 1; k++) //前半段和
                sum1 = sum1 + coin[k];
            for(int k = low + (high - low)/2 + 1; k <= high; k++) //后半段和
                sum2 = sum2 + coin[k];
            if(sum1 > sum2) return FalseCoin(coin, low + (high - low)/2 + 1, high);
            else{
                if(sum2 > sum1)
                    return FalseCoin(coin, low, low + (high - low)/2 - 1);
                else
                    return low + (high - low)/2 + 1;
            }
        }
    }

    //数组初始化,设置其中一枚为假的
    private static void initialization(int[] coin) {
        for(int i = 0; i < coin.length; i++)
            coin[i] = 2;
        int index = (int)(Math.random() * (coin.length));
        coin[index] = 1;
    }

运行结果

在30枚银币中,第2枚是假的

概率算法思想

  概率算法依照概率统计的思路来求解问题,其往往不能得到问题的精确解,但是在数值计算领域得到了广泛的应用。因为很多数学问题,往往没有或者很难计算,这时候便需要通过数值计算来求解近似值。

概率算法基本思想

  概率算法执行的基本过程如下:
  (1)将问题转化为相应的几何图形S,S的面积是容易计算的,问题的结果往往对应几何图形中某一部分S1的面积。
  (2)然后,向几何图形中随机撒点。
  (3)统计几何图形S中和S1中的点数。根据S的面积和S1面积的关系以及各图形中的点数来计算得到结果。
  (4)判断上述结果是否在需要的精度之内,如果未达到精度则进行执行步骤(2),如果达到精度,则输出近似结果。

  概率算法大致分为如下4种形式

  • 数值概率算法
  • 蒙特卡罗(Monte Carlo)算法
  • 拉斯维加斯(Las Vegas)算法
  • 舍伍德(Sherwood)算法

实例

  通过一个实例来看看蒙特卡罗(Monte Carlo)概率算法的应用。蒙特卡罗算法的一个典型应用便是计算圆周率z。

java

public static void main(String[] args) {
        System.out.println("蒙特卡罗概率算法计算∏");
        Scanner sc = new Scanner(System.in);
        System.out.print("输入点的数量:");
        int num = sc.nextInt();  //输入撒点个数
        double PI = MontePI(num); //计算PI
        System.out.println("PI=" + PI);
    }

    private static double MontePI(int num) {
        double x, y;
        int sum = 0;
        for(int i = 0; i < num; i++){
            x = Math.random(); //产生0~1之间的一个随机数
            y = Math.random(); //产生0~1之间的一个随机数
            if((x * x + y * y) <= 1) //计数,落在阴影中的点数
                sum ++; 
        }
        return (double)(4 * sum) / num;
    }

运行结果

蒙特卡罗概率算法计算∏
输入点的数量:50000000
PI=3.1418696
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值