0
点赞
收藏
分享

微信扫一扫

JAVA 最长路径 (递归回溯深搜dfs)

艾晓雪 2022-02-25 阅读 116

JAVA 最长路径 (递归回溯/深搜dfs)

题目一

Description
把m * n的方地划分成m*n格,每格上标上一个整数。当相信邻的的两格数据一样或相差为1时就可以连通。请找出最长的连通路线。注意只能上下左右四个方向移动。例如:

img

的长度为21.

Input
有多个案例,每个案例先输入两个整数m、n,接着有m行n列的数。这两数在50以内。

Ouput
输出最长路径的长度。

Code1

public class Main {
	/**
	 * a b 表示a行b列
	 * road表示读入的a行b列矩阵
	 * flag用来标记可以走通的路径
	 * t 表示四种移动方式:上下左右
	 * maxLen 表示最长路径
	 */
    static int a,b;
    static int[][] road,flag;
    static int[][] t = {{0,-1},{0,1},{-1,0},{1,0}};
    static int maxLen;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        while(in.hasNext()) {
        	 maxLen=-1;
        	 a = in.nextInt();
        	 b = in.nextInt();
        	road = new int[a][b];
        	for(int i=0;i<a;i++)
        		for(int j=0;j<b;j++)
        			road[i][j] = in.nextInt();
        	
        	//从(i,j)开始移动
        	for(int i=0;i<a;i++)
        	{
        		for(int j=0;j<b;j++) {
        			//每次出发前将用来标记的flag初始化
        			flag = new int[a][b];
        			//标记出发点(i,j)为1
        			flag[i][j] = 1;
        			//从(i,j)开始走,这时路径长度为1
        			dfs(i,j,1);
        		}
        	}
        	System.out.println(maxLen);	
        }
       in.close();
	}
	/**
	 * @param num 计算路径长度
	 */
  public static void dfs(int x,int y,int num) {
	  //(dx,dy)表示与(x,y)相邻的点
	  for(int n=0;n<4;n++) {//有四种移动方法,回溯
		  int dx = x+t[n][0];//左右移动
		  int dy = y+t[n][1];//上下移动
		  /* 1.dx>=0 && dx<a && dy>=0 && dy<b 判断是否在矩阵内【防止越界】
		   * 2.Math.abs(road[x][y]-road[dx][dy])==1||road[x][y]==road[dx][dy]
		   * 判断相邻的的两格数据是否一样或相差为1
		   * */
		  if(dx>=0 && dx<a && dy>=0 && dy<b && flag[dx][dy]==0 && (Math.abs(road[x][y]-road[dx][dy])==1||road[x][y]==road[dx][dy]))
		  {
			  //假定该相邻点可以连通,标记为1
			 flag[dx][dy] = 1;
			 //继续移动
			 dfs(dx,dy,num+1);
			 //走不通,标记为0
			 flag[dx][dy]=0;
		  }
			  
	  }
	  if(num>maxLen) {
		  maxLen=num;
	  }
	  
  }
}

题目二

1219. 黄金矿工

你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0

为了使收益最大化,矿工需要按以下规则来开采黄金:

  • 每当矿工进入一个单元,就会收集该单元格中的所有黄金。
  • 矿工每次可以从当前位置向上下左右四个方向走。
  • 每个单元格只能被开采(进入)一次。
  • 不得开采(进入)黄金数目为 0 的单元格。
  • 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

Code2

// 递归回溯 / 深搜 dfs
public class GetMaximumGold {

    public static final int[][] GRID1 = {
            {1, 0, 7},
            {2, 0, 6},
            {3, 4, 5},
            {0, 3, 0},
            {9, 0, 20}
    };
    public static final int[][] GRID2 = {
            {0, 6, 0},
            {5, 8, 7},
            {0, 9, 0}
    };

    public static void main(String[] args) {
        System.out.println(getMaximumGold(GRID1));
        System.out.println(getMaximumGold(GRID2));
    }

    public static int getMaximumGold(int[][] grid) {
        int maxLen = 0, m = grid.length, n = grid[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] != 0) 
                    maxLen = Math.max(maxLen, getGold(grid, i, j));
            }
        }
        return maxLen;
    }

    // four directions
    public static final int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    public static int getGold(int[][] grid, int i, int j) {
        if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0;

        int len = grid[i][j];
        grid[i][j] = 0;     // 开采完置为零, 根据规则,不会原路返回

        int maxLen = -1;
        // 上下左右的顺序
        for (int[] direction : directions) {
            int di = i + direction[0], dj = j + direction[1];
            maxLen = Math.max(maxLen, getGold(grid, di, dj));
        }
        grid[i][j] = len;   // DFS回溯的常规操作: 恢复现场

        return maxLen + len;
    }
    
}
举报

相关推荐

0 条评论