文章目录
1. 枚举
- 简述
- 尝试搜索空间内所有可能的解
- 搜索空间越大,使用枚举进行搜索的复杂度就越高
- 百鸡问题
-
题目:用小于等于 n 元去买 100 只鸡,大鸡 5 元/只,小鸡 3 元/只,还有 1/3 元每只的一种小鸡,分别记为 x 只,y 只,z 只。编程求解 x,y,z 所有可能解。
-
解决方式:暴力枚举
-
方法:
public static void HundredChicks(int sum){ for (int i = 0; i <= 100; i++) { for (int j = 0; j <= 100-i; j++) { int z = 100 -i -j; // 采用对不等式两端所有数字都乘3的操作,避免除法带来的精度损失 if(i*5*3+j*3*3+z < sum*3) System.out.println("x="+i+", y="+j+", z="+z); } } }
-
总结:在复杂度允许的范围内,直白的枚举思路简单,代码清晰,所以在一些看似无从下手的题目面前,我们要换个角度,试着从更暴力的角度去思考
2.2 BFS
- 算法
-
问题的解空间内有若干可能的状态,每一次状态迁移都从这些可能状态中选择一个执行;
-
包含搜索空间中所有状态的树:解答树
- 所谓广度优先搜索,即在遍历解答树时使每次状态转移时扩展出尽可能多的新状态,并且按照各个状态出现的先后顺序依次扩展它们。
- 所谓广度优先搜索,即在遍历解答树时使每次状态转移时扩展出尽可能多的新状态,并且按照各个状态出现的先后顺序依次扩展它们。
-
剪枝:
- 剪去解答树中不可能是我们所需答案的子树,减少所有范围,提高搜索效率;
-
使用队列实现:
- 将每次扩展得到的新状态放入队列中;
- 只有排在该状态之前的所有状态都被扩展完成,才对此状态进行扩展;
-
使用标记数组:
- 为防止对无效状态的重复搜索,增加标记数组;
- 当已经访问过一个状态后,将其状态在标记数组中对应的位置进行标记(true/false)
- 迷宫问题
- 题目简述:
Ignatius 被魔王抓走了,有一天魔王出差去了,这可是 Ignatius 逃亡的好机会. 魔王住在一个城堡里,城堡是一个 ABC 的立方体,可以被表示成 A 个 B*C 的矩 阵,刚开始 Ignatius 被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现 在知道魔王将在 T 分钟后回到城堡,Ignatius 每分钟能从一个坐标走到相邻的六个 坐标中的其中一个.现在给你城堡的地图,请你计算出 Ignatius 能否在魔王回来前 离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃 亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1。
- 三维迷宫,从 {0,0,0} 出发,到达对角线出口即为胜利;
- 迷宫中 1 表示墙,0 表示路;
static boolean[][][] mark;
static int[][][] maze = {
{
{
0,1,1,1}, {
0,0,1,1}, {
0,1,1,1}}, {
{
1,1,1,1}, {
1,0,0,1}, {
0,1,1,1}}, {
{
0,0,0,0}, {
0,1,1,0}, {
0,1,1,0}}};
static int[][] options = {
{
1,0,0}, {
-1,0,0}, {
0,1,0}, {
0,-1,0}, {
0,0,1}, {
0,0,-1}};
static Queue<Cell> queue = new LinkedList<>();
static int BFS(int a, int b, int c){
while (!queue.isEmpty()){
Cell cell = queue.poll();
int x = cell.x, y = cell.y, z = cell.z;
for (int i = 0; i < options.length; i++) {
x = cell.x + options[i][0];
y = cell.y + options[i][1];
z = cell.z + options[i][2];
//排除特殊情况,当前前进目标不在迷宫内、当前位置已访问或当前位置是墙,则跳过该位置
if ( x<0 || x>a-1 || y<0 || y>b-1 || z<0 || z>c-1) continue;
if (mark[x][y][z]) continue;
if (maze[x][y][z]==1) continue;
Cell new_cell = new Cell(x, y, z, cell.time+1);
queue.offer(new_cell);
mark[x][y][z] = true;
if(x==a-1&&y==b-1&&z==c-1) return ne