JAVA算法:DFS算法题解两个例子(走迷宫和求排列组合数)

DFS算法题解两个例子(走迷宫和求排列组合数)

用DFS算法来求解几道题目。典型的问题是走迷宫问题。

####走迷宫题目描述

给定一个M*N的矩阵(二维数组),分别用0和1表示通路和障碍物。即 0 表示 通路;1 表示 障碍物。从矩阵的左上角开始,每次只能向右,下,左,上移动位置,不能斜着走。请给出从入口到出口的路线。

走迷宫

怎么开始思考呢?
首先想想,这个题目其实是找从入口(Entrance)到出口(Exit)的可能的路径。矩阵(二维数组)从左上角开始,坐标为(0,0),可以向右走,坐标为(0,1);或者向下走,坐标为(1,0)。对于一般的位置(x,y),可以有4个搜索方向:右(x,y+1),下(x+1,y),左(x,y-1),上(x-1,y)。

走迷宫DFS算法问题

如何设计DFS搜索函数呢?

二维数组(M行,N列)的右下角出口位置可以表示为:(m-1, n-1)
路径表示为path ; 但是路径可能有很多条,其中最短的路径表示为:shortestPath。

至少这个函数需要三个参数。dfs(x坐标,y坐标,搜索矩阵即二维数组)

所定义dfs函数为:

public static void dfsMaze(int x,int y, int[][] maze)

然后设计搜索结束返回的判断条件

//设置结束条件        
        if (x < 0 || y < 0)  
            return;  
        // 如果坐标越界,或者 maze[x][y]==1 表示遇到障碍
        if (x > m - 1 || y > n - 1 || maze[x][y] ==1)  
            return;  
        //表示遇到障碍
        if (maze[x][y] == 1)  
            return; // 判断是否通路和越界  

判断是否达到出口位置

if (x == m - 1 && y == n - 1) { // 判断是否抵达出口  
        	path = path + "(" + x + "," + y + ")";   
        	if (shortestPath.length() == 0 || shortestPath.length() > shortestPath.length())  
        		shortestPath = path; 
            System.out.println("找到路线:" + path);  
            return;  
        }  

对于任意位置(二维数组的某一个位置)因为0代表通路,1代表障碍物,如果走过了可以到达的位置,将其设定一个标记为1

maze[x][y] = 1; // 将走过的路标记。当改路线搜索完成时,再清除此标记为0。  

搜索方向可以表示为:

// 向四个方向搜索  
        dfsMaze(x + 1, y, maze);  //向右搜索
        dfsMaze(x, y + 1, maze);  //向下搜索
        dfsMaze(x, y - 1, maze);  //向上搜索
        dfsMaze(x - 1, y, maze);  //向左搜索

它表示从上一个位置开始,向下一个位置搜索的坐标。

完整的代码如下所示:

package com.bean.algorithmbasic;

public class DFSMaze {

	/**
	 * DFS算法解决走迷宫问题
	 * 0: 表示通路
	 * 1: 表示死路
	 * 
	 */
	static String path = "";  
	static String shortestPath = "";
          
    public static void dfsMaze(int x, int y, int[][] maze) {  
    	/*
    	 * 获得矩阵的大小
    	 * */
    	int m=maze.length;  
        int n=maze[0].length;  
        //设置结束条件        
        if (x < 0 || y < 0)  
            return;  
        // 如果坐标越界,或者 maze[x][y]==1 表示遇到障碍
        if (x > m - 1 || y > n - 1 || maze[x][y] ==1)  
            return;  
        //表示遇到障碍
        if (maze[x][y] == 1)  
            return; // 判断是否通路和越界  
        if (x == m - 1 && y == n - 1) { // 判断是否抵达出口  
        	path = path + "(" + x + "," + y + ")";   
        	if (shortestPath.length() == 0 || shortestPath.length() > shortestPath.length())  
        		shortestPath = path; 
            System.out.println("找到路线:" + path);  
            return;  
        }  
        
        String temp = path;  
        path = path + "(" + x + "," + y + ")" + "-"; // 记录路线  
        maze[x][y] = 1; // 将走过的路标记  
        // 向四个方向搜索  
        dfsMaze(x + 1, y, maze);  //向右搜索
        dfsMaze(x, y + 1, maze);  //向下搜索
        dfsMaze(x, y - 1, maze);  //向上搜索
        dfsMaze(x - 1, y, maze);  //向左搜索
        // 将路线和标记恢复成上一次的状态  
        maze[x][y] = 0;  
        //清除
        path = temp;  
    }  

	public static void main(String[] args) {
		// 初始化一个迷宫地图
		// 0: 表示通路
		// 1:表示死路
		int[][] maze = { 
				{0, 0, 1, 1, 1, 1, 1, 1, 1},  
                {1, 0, 0, 0, 0, 0, 0, 0, 1},  
                {1, 0, 1, 1, 0, 1, 1, 0, 1},  
                {1, 0, 1, 0, 0, 1, 0, 0, 1},  
                {1, 0, 1, 0, 1, 0, 1, 0, 1},  
                {1, 0, 0, 0, 0, 0, 1, 0, 1},  
                {1, 1, 0, 1, 1, 0, 1, 1, 1},  
                {1, 0, 0, 0, 0, 0, 0, 0, 0},  
                {1, 1, 1, 1, 1, 1, 1, 1, 0}
				};
		
		int[][] maze2 = { 
				{0, 0, 1, 1, 1, 1, 1, 1, 1},  
                {1, 0, 0, 0, 0, 0, 0, 0, 1},  
                {1, 0, 1, 1, 0, 1, 1, 0, 1},  
                {1, 0, 1, 0, 0, 1, 0, 0, 1},  
                {1, 0, 1, 0, 1, 0, 1, 0, 1},  
                {1, 0, 0, 0, 0, 0, 1, 0, 1},  
                {1, 1, 0, 1, 1, 0, 1, 0, 1},  
                {1, 0, 0, 0, 0, 0, 1, 0, 0},  
                {1, 1, 1, 1, 1, 1, 1, 1, 0}
				};
		/*
		 * 从矩阵的左上角位置开始搜索
		 * */
		dfsMaze(0, 0, maze); 
		if (shortestPath.length() != 0)  
            System.out.println("最短路线为:" + shortestPath);  
        else  
            System.out.println("没有找到路线!");  
       

	}

}

运行结果为:

找到路线:(0,0)-(0,1)-(1,1)-(2,1)-(3,1)-(4,1)-(5,1)-(5,2)-(6,2)-(7,2)-(7,3)-(7,4)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
找到路线:(0,0)-(0,1)-(1,1)-(2,1)-(3,1)-(4,1)-(5,1)-(5,2)-(5,3)-(5,4)-(5,5)-(6,5)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
找到路线:(0,0)-(0,1)-(1,1)-(1,2)-(1,3)-(1,4)-(2,4)-(3,4)-(3,3)-(4,3)-(5,3)-(5,4)-(5,5)-(6,5)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
找到路线:(0,0)-(0,1)-(1,1)-(1,2)-(1,3)-(1,4)-(2,4)-(3,4)-(3,3)-(4,3)-(5,3)-(5,2)-(6,2)-(7,2)-(7,3)-(7,4)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
最短路线为:(0,0)-(0,1)-(1,1)-(2,1)-(3,1)-(4,1)-(5,1)-(5,2)-(6,2)-(7,2)-(7,3)-(7,4)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)

这里有一个问题,如果最短的路线不只一条,怎么处理?这个算法中并没有考虑这个问题。
所以这个算法还是有一定的瑕疵的。

####求排列组合数

假设给定3个数:1,2,3,求出其所有的排列组合情况。

例如:
1,1,1
1,1,2
1,1,3
1,2,1
1,2,2
1,2,3
……

3,3,3

这个问题也可以使用DFS算法求解。

那么该如何开始思考这个问题呢?

首先定义一个数组:

int[] array = new int[3];

数组元素表示为:array[0]=1; array[1]=2;array[2]=3

这个数组代表搜索的开始。从array[0]开始,第一种情况组合就是:1,1,1

设计DFS搜索函数的原型为:

public void dfsExample(int index)

其中:参数的含义是从目标数组中依次取出第几个元素。index代表数组元素的下标。

边界条件为:

// 边界条件
	    if (index == 3)
	    {
	    	
	        for (int i = 0; i < 3; i++)
	        {
	            System.out.print(array[i]+" ");
	        }
	        System.out.println();
	        //走不下去了就 return了
	        return;
	    }

搜索过程为:

for (int i = 1; i <= 3; i++)
	    {
	    	array[index] = i;
            // index+1 枚举下一种情况
	        dfsExample(index+1);
	    }

完整的算法设计如下:

package com.bean.algorithmbasic;

public class DFSDemo {
	
	int[] num = new int[3];
	
	public void dfsExample(int index)
	{
		
		// 边界条件
	    if (index == 3)
	    {
	    	
	        for (int i = 0; i < 3; i++)
	        {
	            System.out.print(num[i]+" ");
	        }
	       
	        System.out.println();
	        
	        //走不下去了就 return了
	        return;
	    }

	    for (int i = 1; i <= 3; i++)
	    {
	        num[index] = i;
            // index+1 枚举下一种情况
	        dfsExample(index+1);
	    }
	    
	}

	public static void main(String[] args) {
		DFSDemo dfsdemo=new DFSDemo();
		dfsdemo.dfsExample(0);   
	}

}

输出结果如下所示:

1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
2 1 1
2 1 2
2 1 3
2 2 1
2 2 2
2 2 3
2 3 1
2 3 2
2 3 3
3 1 1
3 1 2
3 1 3
3 2 1
3 2 2
3 2 3
3 3 1
3 3 2
3 3 3

这两个题目的求解结果并不重要,重要的是需要整理清楚在使用DFS算法思想求解问题时,该如何入手思考问题。
有一些思路还需要在继续思考。
(还没有完全思考清楚)

(完)

  • 54
    点赞
  • 204
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
问题描述: 假设你是一名学校的校长,你需要安排最少的考试时间来安排所有的课程。每个课程都必须在一天内完成,而且一天只能进行一场考试。每个课程都有一些必须先修的课程,因此安排一个课程之前必须先安排所有先修课程的考试。给定课程的总和它们的先修关系列表,你需要编写一个算法来计算完成所有课程所需的最短时间。 输入格式: 第一行包含两个numCourses和prerequisites.length,分别表示课程目和先修关系目。 接下来prerequisites.length行,每行包含两个u和v,表示课程u的先修课程是v。 输出格式: 如果无法完成所有课程,则输出空列表[];否则,按照完成所有课程所需的最短时间的顺序,返回一个课程列表。 算法思路: 这是一个典型的拓扑排序问题,可以使用BFS算法解决。首先,我们需要建立一个图来表示课程之间的依赖关系,并计算每个课程的入度。然后,我们将所有入度为0的课程加入队列中,并在处理它们时,将它们的后继课程的入度减1。如果某个课程的入度为0,则将其加入队列中。当队列为空时,我们就处理完了所有的课程。如果此时我们已经处理完的课程小于总课程,则说明存在环,无法完成所有课程;否则,我们就按照处理顺序返回课程列表即可。 Java代码实现: public class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { int[] inDegree = new int[numCourses]; List<List<Integer>> adj = new ArrayList<>(); for (int i = 0; i < numCourses; i++) { adj.add(new ArrayList<>()); } for (int[] p : prerequisites) { inDegree[p[0]]++; adj.get(p[1]).add(p[0]); } Queue<Integer> queue = new LinkedList<>(); for (int i = 0; i < numCourses; i++) { if (inDegree[i] == 0) { queue.offer(i); } } int[] res = new int[numCourses]; int index = 0; while (!queue.isEmpty()) { int course = queue.poll(); res[index++] = course; for (int c : adj.get(course)) { if (--inDegree[c] == 0) { queue.offer(c); } } } return index == numCourses ? res : new int[0]; } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值