P1123 取数游戏
P1123 取数游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
分析:
- 贪心
每次去最大值,因为没每取一个数,相邻的数就不能再取,每次决策都会影响下次结果,不可取- 动规
同上,也不可取- 数据量较小,考虑 dfs
思路:
- 一个数有取与不取两种状态,状态改变取决于周围取数的变化。用 mark[ i ] [ j ] 记录点 ( i , j ) 附近有几个数,若 mark[ i ] [ j ] == 0 就说明这个数可以取
方向数组
方向数组常应用于搜索算法中,在c/c++中可以用二维数组来表示方向。例如二维数组a[k][n]
含义就是方向数组里面储存了k个向量,而n则代表每个向量有n维(n一般为2)。下面我们由下图来讲解方向数组如何控制方向。
上图是(x,y)这个点八个方向的坐标,在c/c++中x和y并不是我们数学中的坐标系而是数组的行数(x对应行数)和列数(y对应列数)。
public class P1123 {
// 这里的存储数的二维数组非常有讲究,自己琢磨一下(截图中也有说明)
static int[][] arr = new int[7][7];// 存放数字的矩阵,开的数字比题目要求范围大 1
static int[][] vis = new int[9][9];// 标记矩阵中对应位置的数字有没有被访问(取数),开的数组比原数组大 2
static int n;// n 行
static int m;// m 列
// ↓ 方向数组用来控制搜索时的方向,用排列组合来求不会出错
static int[][] d = { { 1, 0 }, { 1, -1 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, 1 } };
static int max;
static int sum;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
for (int i = 0; i < t; i++) {// 共运行 t 次
max = 0;
sum = 0;
for (int k = 0; k < 9; k++) {// 每一次都要对vis数组进行初始化
for (int j = 0; j < 9; j++) {
vis[k][j] = 0;
}
}
n = scanner.nextInt();
m = scanner.nextInt();
for (int k = 1; k <= n; k++) {// 输入数据矩阵中的数字
for (int j = 1; j <= m; j++) {
arr[k][j] = scanner.nextInt();
}
}
dfs(1, 1);// 从 (1, 1) 的位置开始搜索
System.out.println(max);
}
}
private static void dfs(int x, int y) {
if (y >= m + 1) {// 此行搜索完,搜索下一行
dfs(x + 1, 1);
return;
}
if (x >= n + 1) {// 搜索完毕
max = Math.max(sum, max);
return;
}
if (vis[x][y] == 0) {// 取此数
sum += arr[x][y];
for (int i = 0; i < 8; i++) {
vis[x + d[i][0]][y + d[i][1]]++;
}
dfs(x, y + 1);// 取下一个数
sum -= arr[x][y];// 回溯
for (int i = 0; i < 8; i++) {
vis[x + d[i][0]][y + d[i][1]]--;
}
}
dfs(x, y + 1);// 不取此数,取下一个数
}
}