算法设计-枚举案例

思维导图:
在这里插入图片描述

枚举思想:
枚举是基于已有知识进行答案猜测的问题求解策略。

枚举中的三个问题:
问题一

  • 给出解空间,建立简洁的数学模型
  • 可能的情况是什么
  • 模型中变量数尽可能少,他们之间相互独立
    1、“求小于N的最大素数”中的条件是“n不能被[2,n)中任意一个素数整除”
    2、而不是"n不能被[2,n)中任意一个整数整除"
    问题二
  • List item减少搜索的空间
  • 利用知识缩小模型中各变量的取值范围,避免不必要的计算
    1、减少代码中循环体执行次数
    2、除2之外,只有奇数才可能是素数,{2, 2i+1|1<=i, 2+1<=i, 2*+1<n}
    问题三
  • 采用合适的搜索顺序
  • 搜索空间的遍历顺序要与模型中条件表达式一致
    1、对{2, 2i+1|1<=i, 2+1<n},按照从小到大的顺序

3、素数问题:
代码实现:

public class PrimeNumber {
    public static void main(String[] args) {
        long time = System.currentTimeMillis();
        for (int i = 1; i <= 100; i++) {  //遍历一百之内的数
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean flag = true;//假设这个数是素数
            for (int j = 2; j < i; j++) {
                if (i % j == 0) { //i是j的素数
                    flag = false;//找到一个就可以了
                    break;
                }
            }
            if (flag) { //判断这个数是素数
                System.out.print(i + "\t");
            }
        }
        long time2 = System.currentTimeMillis();
        System.out.println("本段代码执行效率" + (time2 - time) + "毫秒");
    }

}

4、百鸡百钱:

代码实现:
public class ChickenMoney {
@Test
public void testFun02(){
    for(int x=0; x<=100; x++){
        for(int y=0; y<=100-x; y++){
            int z = 100 - x - y;
            if(z % 3 == 0){
                if(5*x + 3*y + z/3 == 100)
                    System.out.println("鸡翁 " + x + "只,鸡母 " + y + "只,鸡 雏 " + z + "只!");
            }
        }
    }
}
}

5、生理周期

代码实现:
public class PhysiologicalCycle {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入您要测试的数组:");
        int n= scan.nextInt();
        while(n-->0){
            System.out.println("请输入体力高峰期在本年第一天出现的天数:");
            int p= scan.nextInt();
            System.out.println("请输入情感高峰期在本年第一天出现的天数:");
            int e= scan.nextInt();
            System.out.println("请输入智力高峰期在本年第一天出现的天数:");
            int i= scan.nextInt();
            System.out.println("请输入今年给定第一天出现的天数:");
            int d= scan.nextInt();
            System.out.printf("Case%d:the next triple peak occurs in %d days.\r\n",(6-n),nextTriplePeak(p,e,i,d));
        }
    }

    private static int nextTriplePeak(int p, int e, int i, int d) {
        int j;
        for (j=d+1;j<21252;j++){      //枚举每一天
            if ((j-p)%23==0){           //找到第一个体力高峰期
                break;
            }
        }
        for(;j<21252;j+=23){        //枚举每一个体力高峰日
            if ((j-e)%28==0){       //找到第一个体力与情感的共同高峰日
                break;
            }
        }
        for (;j<21252;j+=23*28){    //枚举每一个体力与情感的共同高峰日
            if ((j-i)%33==0){
                break;
            }
        }
        return j-d;
    }

}

6、完美立方

代码实现:
public class PerfectCube {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入大于1的,不大于100的正整数:");
        int n = scan.nextInt();
        int a, b, c, d;//枚举完美立方等式四个数用的变量
        // 为了方便后续的代码执行,将2-n的立方存储到一个数组中
        int[] cube = new int[n + 1];
        for (int i = 2; i <= n; i++)
            cube[i] = (int) Math.pow(i, 3);
        // 开始枚举
        for (a = 6; a <= n; a++) {             //枚举a
            for (b = 2; b < a; b++) {          //枚举b
                for (c = b; c < a; c++) {      //枚举c
                    for (d = c; d < a; d++) {  //枚举d
                        if (cube[a] == cube[b] + cube[c] + cube[d])
                            System.out.printf("Cube=%d,Triple=(%d,%d,%d)\r\n", a, b, c, d);
                    }
                }
            }
        }
    }
}

7、熄灯问题

代码实现:
public class TurnOffLights {
    static int[][] puzzle = new int[6][8];
    static int[][] press = new int[6][8];
    /**
     * 该方法用于判断press是否是合理的解
     *
     * @return 返回true,表示press是一个解,否则不是
     */
    private static boolean guess() {
        /*
         * 根据press第1行和puzzle数组,计算press第2、3、4行的值
         */
        for (int r = 1; r < 5; r++) {
            for (int c = 1; c < 7; c++) {
                press[r + 1][c] = (puzzle[r][c] + press[r - 1][c] +
                        press[r][c]
                        + press[r][c - 1] + press[r][c + 1]) % 2;
            }
        }
        /*
         * 判断所计算的press数组能否熄灭第5行的所有灯
         */
        for (int c = 1; c < 7; c++) {
            if ((press[5][c - 1] + press[5][c] + press[5][c + 1] + press[4]
                    [c]) % 2 != puzzle[5][c])
                return false;
        }
        return true;
    }

    private static void enumerate() {
        int c;
        for (c = 1; c < 7; c++)
            press[1][c] = 0;
        while (!guess()) {
            press[1][1]++;
            c = 1;
            /*
            对press第1行的元素press[1][1]~press[1][6]各种取值情况进行枚举
            */
            while (press[1][c] > 1) {
                press[1][c] = 0;
                c++;
                press[1][c]++;
                if (c == 7)
                    break;
            }
        }
    }

    public static void main(String[] args) {
        System.out.println("请输入你要测试的案例次数...");
        Scanner scan = new Scanner(System.in);
        int cases = scan.nextInt();
        // 给下标为0和下标为7的列,赋值为1,表示不需要操作
        for (int r = 0; r < 6; r++)
            press[r][0] = press[r][7] = 0;
        // 将第一行的按钮,全部置0,因为c为0和7已经处理过了,所以这里处理1~6
        for (int c = 1; c < 7; c++)
            press[0][c] = 0;
        // 每一次,让用户给puzzle赋值
        for (int i = 0; i < cases; i++) {
            for (int r = 1; r < 6; r++) {
                System.out.println("请输入第" + r + "行的6盏灯的状态...");
                String str = scan.next();
                for (int c = 1; c < 7; c++) {
                    char cha = str.charAt(c - 1);
                    puzzle[r][c] = Integer.parseInt(String.valueOf(cha));
                }
            }
            System.out.println("本次测试的灯的状态用矩阵表示为...");
            System.out.println(Arrays.deepToString(puzzle));
            // 用户完成对puzzle的元素值的输入后,进行枚举
            enumerate();
            System.out.printf("PUZZLE #%d\n", i + 1);
            for (int r = 1; r < 6; r++) {
                for (int c = 1; c < 7; c++)
                    System.out.printf("%d ", press[r][c]);
                System.out.println();
            }
        }
    }
}

8、讨厌的青蛙
代码实现:

package com.zpark.chapterthress;

import java.util.Scanner;

/**
 * @Title: NastyFrog1
 * @Author Charles
 * @Package com.zpark.chapterthress
 * @Date 2022/10/26 19:30
 */
public class NastyFrog1 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int i, j, dX, dY, pX, pY, steps, max = 2;

        System.out.println("请输入稻田的行数");
        int r = scan.nextInt();
        System.out.println("请输入稻田的列数");
        int c = scan.nextInt();
        System.out.println("请输入被踩踏的稻子数目");
        int n = scan.nextInt();
        Plant[] plants = new Plant[n];
        for(i = 0; i < n; i++){
            plants[i] = new Plant(r,n);
            System.out.println("请输入第" + (i + 1) + "棵被踩踏水稻的x坐标");
            plants[i].setX(scan.nextInt());
            System.out.println("请输入第" + (i + 1) + "棵被踩踏水稻的y坐标");
            plants[i].setY(scan.nextInt());
        }
        for(i = 0; i < n - 1; i++){
            for(j = i + 1; j < n; j++){
                dX = plants[j].getX() - plants[i].getX();
                dY = plants[j].getY() - plants[i].getY();
                pX = plants[i].getX() - dX;
                pY = plants[i].getY() - dY;
// 如果第一点的前一点在稻田里,则本次选的第二点导致的步长过小,不合

                if(pX >= 1 && pX <= r && pY >= 1 && pY <= c)
                    continue;

                if(plants[i].getX() + (max - 1) * dX > r)
                    break;
// 如果y方向过早越界了,也应该换一个点作为第二点再试
                pY = plants[i].getY() + (max - 1) * dY;
                if(pY > c || pY < 1)
                    continue;
// 看看从这两点出发,一共能走几步
                steps = searchPath(plants[j], dX, dY, r, c, plants);
                if(steps > max)
                    max = steps;
            }
            if(max == 2)
                max = 0;
        }
        System.out.println("踩踏最多的那一条路径上,总共有" + max + "棵水稻被踩踏了");
    }

    /**
     * 将水稻数组排序,排序规则:
     * 先按照x坐标从小到大,如果x坐标相等就按照y坐标从小到大排列
     * @param plants 稻田中,被踩踏的所有水稻
     */
    private static void sort(Plant[] plants){
        // 声明一个用于交换的变量
        Plant swapPlant;
        // 冒泡排序
        for(int i = 0 ;i < plants.length - 1; i++){
            for (int j = i + 1; j < plants.length; j++){
                if (plants[i].compare(plants[i],plants[j]) > 0){
                    swapPlant = plants[i];
                    plants[i] = plants[j];
                    plants[j] = swapPlant;
                }
            }
        }
    }

    private static int searchPath(Plant secPlant, int dX, int dY, int r,
                                  int c, Plant[] plants){
        int steps = 2; // 起始点已经是被踩踏的第二棵水稻,故另steps为2。
        boolean flag;
        Plant plant = new Plant();
        plant.setX(secPlant.getX() + dX);
        plant.setY(secPlant.getY() + dY);
        while(plant.getX() <= r && plant.getX() >= 1 && plant.getY() <= c
                && plant.getY() >= 1){
            flag = false;
// 每一步都要踩到水稻才算合理,也就是下一步应该踩踏到一棵被踩踏到的数组
            for (Plant p : plants) {
                if (plant.getX() == p.getX() && plant.getY() == p.getY())
                {
                    flag = true;
                    break;
                }
            }
            if(!flag){

                break;
            }
            plant.setX(plant.getX() + dX);
            plant.setY(plant.getY() + dY);
            steps++;
        }
        return steps;
    }
}

码字不易,点点赞

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值