算法 — 网格贪吃蛇

问题描述

  那个曾经风靡全球的贪吃蛇游戏又回来啦!这次贪吃蛇在m行n列的网格上沿格线爬行,从左下角坐标为(0,0)的格点出发,在每个格点处只能向上或者向右爬行,爬到右上角坐标为(m-1,n-1)的格点时结束游戏。网格上指定的格点处有贪吃蛇喜欢吃的豆豆,给定网格信息,请你计算贪吃蛇最多可以吃多少个豆豆。

输入格式

  输入数据的第一行为两个整数m、n(用空格隔开),分别代表网格的行数和列数;第二行为一个整数k,代表网格上豆豆的个数;第三行至第k+2行是k个豆豆的横纵坐标x、y(用空格隔开)。

输出格式

  程序输出一行,为贪吃蛇可吃豆豆的最大数量。

样例输入

10 10
10
3 0
1 5
4 0
2 5
3 4
6 5
8 6
2 6
6 7
3 1

样例输出

5

数据规模和约定

  1≤m, n≤10^6,0≤x≤m-1,0≤y≤n-1,1≤k≤1000

资源限制

时间限制:1.0s 内存限制:256.0MB

解题思路:

        首先想到的就是通过动态规划进行求解,惯性思维借助二维数组,后来发现是数组的容量已经超过了内存限制,故需要进行改进,原始代码如下:

import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int m = scan.nextInt();//网格行数
		int n = scan.nextInt();//网格列数
		int k = scan.nextInt();//网格上豆豆的个数
		int[][] location = new int[k][2];
		int x, y;
		int[][] map = new int[m][n];//网格地图
		for (int i = 0; i < k; i++) {//豆豆位置
			x = scan.nextInt();
			y = scan.nextInt();
			map[m - 1 -y][x] = 1;
		}
		for (int i = 1; i < n; i++) {//最下面一行(纵坐标为0)的每个位置最大可吃豆豆数
			map[m - 1][i] += map[m - 1][i - 1];
		}
		for (int i = 1; i < m; i++) {//最左边一行最大豆数
			map[m - i - 1][0] += map[m - i][0];
		}
		for (int i = 1; i < m; i++) {
			for (int j = 1; j < n; j++) {
				map[m - i - 1][j] += Math.max(map[m - i - 1][j - 1], map[m - i][j]);
			}
		}
		System.out.println(map[0][n - 1]);
		scan.close();
	}
}

        可以看到,二维数组 map 很大,但是真正有豆豆的位置却很少,考虑极限,二维数组最大的位置是 10^{12} ,而最多的豆豆数量才是 1000,故这里不应该使用数组模拟坐标图直接进行存储。经过深思熟虑后编写出来的改进版代码如下,但是通过率反而下降了,这让我百思不得其解,希望路过的大佬能给鄙人点解一二,不胜感激!

import java.util.*;
public class Main{
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int m = scan.nextInt();// 网格行数
		int n = scan.nextInt();// 网格列数
		int k = scan.nextInt();// 网格上豆豆的个数
		int[][] location = new int[k][2];// 用于存储豆豆初始坐标
		int x, y, i, j, dis, maxX = 0, maxY = 0, size = 0;
		for (i = 0; i < k; i++) {// 豆豆位置
			location[i][0] = scan.nextInt();// 豆豆横坐标,后用于剔除空行
			location[i][1] = scan.nextInt();// 豆豆纵坐标,先用于剔除空行
		}
		/**
		 * 根据纵坐标(行标)进行排序,按照从小到大顺序排列
		 */
		for (i = 0; i < k - 1; i++) {
			for (j = 0; j < k - i - 1; j++) {
				if (location[i][1] > location[i + 1][1]) {// 两个元素进行交换,这里用到较为巧妙的算法,也可以用一个中间变量去过度
					// 交换纵坐标
					location[i][1] = location[i][1] + location[i + 1][1];
					location[i + 1][1] = location[i][1] - location[i + 1][1];
					location[i][1] = location[i][1] - location[i + 1][1];
					// 交换行坐标
					location[i][0] = location[i][0] + location[i + 1][0];
					location[i + 1][0] = location[i][0] - location[i + 1][0];
					location[i][0] = location[i][0] - location[i + 1][0];
				}
			}
		}
		maxY = location[k - 1][1];
		for (i = 0; i < k - 1; i++) {// 纵坐标角度进行去空行
			dis = location[i + 1][1] - location[i][1];// 相邻两个点的纵坐标间距
			if (dis > 1) {// 大于1表示中间有空行,需要移动后一个点
				location[i + 1][1] -= (dis - 1);
			}
		}
		/**
		 * 根据横坐标(列标)进行排序,按照从小到大顺序排列
		 */
		for (i = 0; i < k - 1; i++) {
			for (j = 0; j < k - i - 1; j++) {
				if (location[i][0] > location[i + 1][0]) {// 两个元素进行交换,这里用到较为巧妙的算法,也可以用一个中间变量去过度
					// 交换横坐标
					location[i][0] = location[i][0] + location[i + 1][0];
					location[i + 1][0] = location[i][0] - location[i + 1][0];
					location[i][0] = location[i][0] - location[i + 1][0];
					// 交换纵坐标
					location[i][1] = location[i][1] + location[i + 1][1];
					location[i + 1][1] = location[i][1] - location[i + 1][1];
					location[i][1] = location[i][1] - location[i + 1][1];
				}
			}
		}
		maxX = location[k - 1][0];
		for (i = 0; i < k - 1; i++) {// 横坐标角度进行去空行
			dis = location[i + 1][0] - location[i][0];// 相邻两个点的纵坐标间距
			if (dis > 1) {// 大于1表示中间有空行,需要移动后一个点
				location[i + 1][0] -= (dis - 1);
			}
		}
		size = maxX > maxY ? maxX : maxY;
		int[][] map = new int[size][size];//此规模的地图可以涵盖所有豆豆的坐标
		//对地图进行初始化
		for (i = 0; i < k; i++) {
			map[size - location[i][1] - 1][location[i][0]] = 1;
		}
		for (i = 1; i < size; i++) {//最下面一行(纵坐标为0)的每个位置最大可吃豆豆数
			map[size - 1][i] += map[size - 1][i - 1];
		}
		for (i = 1; i < size; i++) {//最左边一行最大豆数
			map[size - i - 1][0] += map[size - i][0];
		}
		for (i = 1; i < size; i++) {
			for (j = 1; j < size; j++) {
				map[size - i - 1][j] += Math.max(map[size - i - 1][j - 1], map[size - i][j]);
			}
		}
		System.out.println(map[0][size - 1]);
		scan.close();
	}
}

你可能感兴趣的:(算法,算法,java,蓝桥杯)