穷举法的应用

穷举法的基本思想

穷举法(枚举法)的基本思想是:列举出所有可能的情况,逐个判断有哪些是符合问题所要求的条件,从而得到问题的全部解答。
它利用计算机运算速度快、精确度高的特点,对要解决问题的所有可能情况,一个不漏地进行检查,从中找出符合要求的答案。
用穷举算法解决问题,通常可以从两个方面进行分析。
(1)问题所涉及的情况:问题所涉及的情况有哪些,情况的种数可不可以确定。把它描述出来。应用穷举时对问题所涉及的有限种情形必须一一列举,既不能重复,也不能遗漏。重复列举直接引发增解,影响解的准确性;而列举的遗漏可能导致问题解的遗漏。
(2)答案需要满足的条件:分析出来的这些情况,需要满足什么条件,才成为问题的答案。把这些条件描述出来。
只要把这两个方面分析好了,问题自然会迎刃而解。
穷举通常应用循环结构来实现。在循环体中,根据所求解的具体条件,应用选择结构实施判断筛选,求得所要求的解。
穷举法的程序框架一般为:
cnt=0; // 解的个数初值为0
for(k=<区间下限>;k<=<区间上限>;k++) // 根据指定范围实施穷举
if (<约束条件>) // 根据约束条件实施筛选
{
cout<<(<满足要求的解>); // 输出满足要求的解
cnt++; // 统计解的个数
}
有些问题没有明确的区间限制,可根据问题的具体实际试探性的从某个数开始,增值穷举,对每一个数作一判断,若满足条件即输出结果,结束穷举。

               下面为几个穷举法的经典案例及代码实现(Java)

【案例1】硬币方案

有50枚硬币,可能包括4种类型:1元、5角、1角和5分。
已知50枚硬币的总价值为20元,求各种硬币的数量。
例如:2、34、6、8就是一种方案。而2、33、15、0是另一个可能的方案,显然方案不唯一。
编写程序求出类似这样的不同的方案一共有多少种?
代码:

public void show_01() {
    int coin_num = 50, count = 0;// 硬币数量
    int num_yuan, num_5jiao, num_1jiao, num_fen;
    for (num_yuan = 0; num_yuan < 50; num_yuan++)
     for (num_5jiao = 0; num_5jiao < 100; num_5jiao++)
      for (num_1jiao = 0; num_1jiao < 500; num_1jiao++)
        for (num_fen = 0; num_fen < 1000; num_fen++) {
          if ((num_yuan + 0.5 * num_5jiao + 0.1 *                num_1jiao + 0.01 * num_fen) == 20) {
           System.out.println(num_yuan + "," + num_5jiao + ","+ num_1jiao + "," + num_fen);
            count++;
            }
        }
        System.out.println("共有" + count + "种组合方式!");
    }

【案例2】4位分段和平方数

一个4位自然数分为前后两个2位数,若该数等于所分两个2位数和的平方,则称为4位分段和平方数。例如,2025=(20+25)2。
编写程序求出所有4位分段和平方数。
代码:

public void show_02() {
        int i, j, num, count = 0;
        for (num = 1000; num <= 9999; num++) {
            i = num / 100;
            j = num % 100;
            if ((i + j) * (i + j) == num) {
                count++;
                System.out.println(num);
            }
        }
        System.out.println("共有"+count+"个这样的4位分段和平方数");
    }

【案例3】三个三位数

将1、2、…、9共9个数分成三组,分别组成三个三位数,且使这三个三位数构成1:2:3的比例,试求出所有满足条件的三个三位数。
例如:三个三位数192、384、576满足以上条件。
代码:

    //这三个变量之后的案例还会用到
    private int[] v = new int[10];
    private int[] vis = new int[10];
    private int[] bk = new int[10];
   //*******************************
    public void show_03() {
        int num, num2, num3, count = 0;
        for (int i = 0; i < 10; i++)
            v[i] = 0;
        for (num = 100; num < 999; num++) {
            num2 = 2 * num;
            num3 = 3 * num;
            if (num2 <= 999 && num3 <= 999) {
                if (judge(num) && judge(num2)&& judge(num3)) {
               System.out.println(num + "," + num2 + "," + num3);
                    count++;
                }
            }
            for (int i = 0; i < 10; i++)
                v[i] = 0;
        }
        System.out.println("共有" + count + "种组合");
    }

    private Boolean judge(int n) {
        int i = n % 10;
        int j = n / 10;
        j = j % 10;
        int k = n / 100;
        if (v[i] != 0)
            return false;
        else
            v[i] = 1;
        if (v[j] != 0)
            return false;
        else
            v[j] = 1;
        if (v[k] != 0)
            return false;
        else
            v[k] = 1;
        return true;
    }

【案例4】完美运算式

把数字1、2、…、9这9个数字填入以下含加减乘除与乘方的综合运算式中的9个□中,使得该式成立
□^□+□□÷□□-□□×□=0
要求数字1,2,…、9这9个数字在式中都出现一次且只出现一次。
代码:

    public void show_04() {
        int a, b, c, i, j, k;
        for (a = 1; a <= 9; a++)
            for (b = 1; b <= 9; b++)
                for (c = 1; c <= 9; c++)
                    for (i = 12; i <= 98; i++)
                        for (j = 12; j <= 98; j++)
                            for (k = 12; k <= 98; k++) {
        if (i % j == 0) { // i/j不为小数
        for (int t = 0; t < 10; t++) { // 初始化数组
            v[t] = 0;
        }
        int ab = (int) Math.pow(a, b);
        if (_04judge1(a) && _04judge1(b)&& _04judge1(c)
         &&  _04judge2(i)&& _04judge2(j) && _04judge2(k)
         && (ab + i / j - k * c == 0)) {
           System.out.println(a + "^" + b + "+"+ c 
           + "/" + i + "-" + j + "*"+ k + "=0");
        }
       }
     }
    }
    private Boolean _04judge1(int n) {
        if (v[n] == 0) {
            v[n] = 1;
        } else
            return false;
        return true;
    }

    private Boolean _04judge2(int n) {
        int i, j;
        i = n % 10;
        j = n / 10;
        if (v[i] == 0) {
            v[i] = 1;
        } else
            return false;
        if (v[j] == 0) {
            v[j] = 1;
        } else
            return false;
        return true;
    }

【案例5】神奇算式

由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:210 x 6 = 1260,8 x 473 = 3784,27 x 81 = 2187都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么一共有多少种满足要求的算式呢?
代码:

public void show_05() {
        int cnt = 0;
        for (int i = 1000; i <= 10000; i++) {
            for (int a = 0; a < 10; a++) { // 初始化数组
                vis[a] = 0;
            }

            if (judge2(i)) {
                for (int a = 0; a < 10; a++) { // 数组赋值
                    bk[a] = vis[a];
                }
                for (int j = 1; j <= 98; j++) {
                    for (int a = 0; a < 10; a++) { // 数组赋值
                        vis[a] = bk[a];
                    }
                    if (i % j != 0) {// 要求能整除
                        continue;
                    }

                    int k = i / j; // 既得k,j两个数字
                    if (j > k) { // 由乘法交换律可得,除去重复项
                        continue;
                    }
                    if (judge1(j, k)) {
                        System.out.println(j + "*" + k + " = " + i);
                        cnt++;
                    }
                }
            }
        }
        System.out.println("共有" + cnt + "种");
    }

    Boolean judge1(int x, int y) {//判断数字组成是否与i组成相同,相同返回1
        do {
            if (vis[x % 10] == 0) {
                return false;
            }
            vis[x % 10]--;
            x /= 10;
        } while (x != 0);
        do {
            if (vis[y % 10] == 0) {
                return false;
            }
            vis[y % 10]--;
            y /= 10;
        } while (y != 0);
        return true;
    }

    Boolean judge2(int x) {//判断i是否含重复数字,有则返回0,否则返回1
        do {
            if (vis[x % 10] != 0) {
                return false;
            }
            vis[x % 10]++;
            x /= 10;
        } while (x != 0);
        return true;
    }

【案例6】排它平方数

小明正看着 203879 这个数字发呆。
原来,203879 * 203879 = 41566646641
这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。
请找出具有这样特点的所有6位数。
代码:

public void show_06() {
        int num = 0, count = 0;
        // BigInteger x ;
        double result;
        for (int a = 1; a <= 9; a++)
            for (int b = 1; b <= 9; b++)
                for (int c = 1; c <= 9; c++)
                    for (int d = 1; d <= 9; d++)
                        for (int e = 1; e <= 9; e++)
                            for (int f = 1; f <= 9; f++) {
                                //数组赋值
                                for (int t = 0; t <10;t++) {
                                    v[t] = 0;
                                }
                                if (judge3(a)&&judge3(b)
                                && judge3(c)&&judge3(d)
                                && judge3(e) && judge3(f)) {
                                    num = a * 100000 +
                                     b * 10000 + c * 1000 + d
                                            * 100 + e * 10 + f;
                                    result=num*num;//平方之后的结果
                                    if (judge4(num)) {
                                        System.out.println(num +
                                         "平方的结果为:"+ result);
                                        count++;
                                    }

                                }

                            }
        System.out.println("共有" + count + "个这样的6位数");
    }

    private Boolean judge3(int n) {

        if (v[n] == 0)
            v[n] = 1;
        else
            return false;

        return true;
    }

    private Boolean judge4(double n)// 用于判断平方结果
    {
        long s_n = (long) n;

        BigInteger num1 = BigInteger.valueOf(s_n);
        BigInteger num2 = BigInteger.valueOf(s_n);
        BigInteger b_n = num1;
        BigInteger temp;
        BigInteger t = num1.multiply(num1);// 两数相乘
        do {
            temp = t.remainder(BigInteger.valueOf(10));// t%10
            System.out.println(" " + temp);
            b_n =b_n.divide(BigInteger.valueOf(10));// b_n /= 10;
            if (!judge3(Integer.valueOf(temp + "")))
                return false;
        } while (b_n != BigInteger.valueOf(0));
        return true;
    }
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值