加载中...

P1123 取数游戏

P1123 取数游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

分析:

  1. 贪心
    每次去最大值,因为没每取一个数,相邻的数就不能再取,每次决策都会影响下次结果,不可取
  2. 动规
    同上,也不可取
  3. 数据量较小,考虑 dfs

思路:

  1. 一个数有取与不取两种状态,状态改变取决于周围取数的变化。用 mark[ i ] [ j ] 记录点 ( i , j ) 附近有几个数,若 mark[ i ] [ j ] == 0 就说明这个数可以取

方向数组

方向数组常应用于搜索算法中,在c/c++中可以用二维数组来表示方向。例如二维数组a[k][n]含义就是方向数组里面储存了k个向量,而n则代表每个向量有n维(n一般为2)。下面我们由下图来讲解方向数组如何控制方向。

image-20230307201421335

上图是(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);// 不取此数,取下一个数
	}

}

image-20230308110834845

image-20230308111332649

posted @ 2023-03-08 11:17  ChuenSan  阅读(83)  评论(0编辑  收藏  举报