问题描述
那个曾经风靡全球的贪吃蛇游戏又回来啦!这次贪吃蛇在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
分析
考虑使用动态规划来做题
转移方程:
x,y为坐标,get()是为了得到(x,y)是否有豆,有返回1
dp[x][y] = Math.max(dp[x][y], Math.max(dp[x - 1][y], dp[x][y - 1]) + get(x,y,yList))
考虑到m与n巨大,而k有比较小,我选择将矩阵就行压缩。
代码
public class test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
List<Z> list = new ArrayList<>();
int k = sc.nextInt();
for (int i = 0; i < k; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
Z z = new Z(x, y);
list.add(z);
}
//开始进行矩阵压缩
List<Z> xList = list.stream().sorted((a, b) -> a.x - b.x).collect(Collectors.toList());
int count = -1;
int pre = -1;//记录前一个数字
for (int i = 0; i < xList.size(); i++) {
Z z = xList.get(i);
if (z.getX() != pre) {
count++;
}
pre = z.getX();
z.setX(0 + count);
xList.set(i, z);
}
n = count;
List<Z> yList = xList.stream().sorted((a, b) -> a.y - b.y).collect(Collectors.toList());
count = -1;
pre = -1;
for (int i = 0; i < yList.size(); i++) {
Z z = yList.get(i);
if (z.getY() != pre) {
count++;
}
pre = z.getY();
z.setY(0 + count);
yList.set(i, z);
}
m = count;
int[][] dp = new int[++n][++m];
//动态规划
for (int x = 0; x < n; x++) {
for (int y = 0; y < m; y++) {
if (y == 0 && x == 0) {
dp[x][y] = get(x,y,yList);
continue;
}
if (x == 0) {
dp[x][y] = dp[x][y - 1] + get(x,y,yList);
continue;
}
if (y == 0) {
dp[x][y] = dp[x - 1][y] + get(x,y,yList);
continue;
}
dp[x][y] = Math.max(dp[x][y], Math.max(dp[x - 1][y], dp[x][y - 1]) + get(x,y,yList));
}
}
System.out.println(dp[n-1][m-1]);
}
}
使用二分法就行查找,其中y为升序,在y相同时x为升序
static int get(int x, int y, List<Z> list) {
int left = 0, right = list.size();
while (left < right) {
int mid = (left + right) / 2;
Z z = list.get(mid);
if (z.getX() == x && z.getY() == y) return 1;
else if (z.getY() < y) {
left = mid+1;
} else if (z.getY() == y){
if (z.getX()< x){
left = mid+1;
}else {
right = mid;
}
}else right = mid ;
}
return 0;
}
class Z {
int x;
int y;
public Z(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Z{" +
"x=" + x +
", y=" + y +
'}';
}
}