思维导图:
枚举思想:
枚举是基于已有知识进行答案猜测的问题求解策略。
枚举中的三个问题:
问题一
- 给出解空间,建立简洁的数学模型
- 可能的情况是什么
- 模型中变量数尽可能少,他们之间相互独立
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;
}
}
码字不易,点点赞