JAVA 最长路径 (递归回溯/深搜dfs)
题目一
Description
把m * n的方地划分成m*n格,每格上标上一个整数。当相信邻的的两格数据一样或相差为1时就可以连通。请找出最长的连通路线。注意只能上下左右四个方向移动。例如:
的长度为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;
}
}