首页 > 试题广场 >

龙与地下城游戏问题

[编程题]龙与地下城游戏问题
  • 热度指数:4666 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个二维数组map,含义是一张地图,例如,如下矩阵

游戏的规则如下:
1)骑士从左上角出发,每次只能向右或向下走,最后到达右下角见到公主。
2)地图中每个位置的值代表骑士要遭遇的事情。如果是负数,说明此处有怪兽,要让骑士损失血量。如果是非负数,代表此处有血瓶,能让骑士回血。
3)骑士从左上角到右下角的过程中,走到任何一个位置时,血量都不能少于1。为了保证骑土能见到公主,初始血量至少是多少?
根据map,输出初始血量。


输入描述:
第一行两个正整数n,m  ,接下来n行,每行m个整数,代表


输出描述:
输出一个整数,表示答案。
示例1

输入

3 3
-2 -3 3
-5 -10 1
0 30 -5

输出

7
示例2

输入

2 2
1 1
1 1

输出

1

备注:
时间复杂度,额外空间复杂度
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,m;
    cin>>n>>m;
    vector<vector<int>>map(n,vector<int>(m));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>map[i][j];
    int more = max(n, m), less = min(n, m);
	bool rowmore = more == n;
	vector<int>dp(less);
	int tmp = map[n - 1][m - 1], row = 0, col = 0;
	dp[less - 1] = tmp > 0 ? 1 : -tmp + 1;
	for (int j = less - 2; j >= 0; j--){
		row = rowmore ? more - 1 : j;
		col = rowmore ? j : more - 1;
		dp[j] = max(dp[j + 1] - map[row][col], 1);
	}
	int c1 = 0, c2 = 0;
	for (int i = more - 2; i >= 0; i--){
		row = rowmore ? i : less - 1;
		col = rowmore ? less - 1 : i;
		dp[less - 1] = max(dp[less - 1] - map[row][col], 1);
		for (int j = less - 2; j >= 0; j--){
			row = rowmore ? i : j;
			col = rowmore ? j : i;
			c1 = max(dp[j] - map[row][col], 1);
			c2 = max(dp[j + 1] - map[row][col], 1);
			dp[j] = min(c1, c2);
		}
	}
	cout<< dp[0];
    return 0;
}

发表于 2019-08-31 21:36:58 回复(0)
这题使用动态规划的方法来解。我们以示例为例来解释。
1.假设矩阵只有一个值,也就是右下角的-5,那么骑士需要6点血。
2.对于最下面一行来说,只能往右走,所以可以求出进入每一格需要的血量。在30这里,设需要的血量为x,进入下一格需要6点血,那么应该有x + 30 >=6,  x >= -24, 算出来x小于0,说明这个格子是加血的,并且加的血足够,x = 1就可以了。那么最下面一行依次就是,{1,1,6}。同理最右边一列是{2,5,6}。
3.接下看递推公式,用hpMatrix表示骑士从任意一格到达终点所需要的最少血量,matrix表示输入矩阵。对于任意一格matrix[i][j]来说,骑士进入它并且能够成功到达终点所需要的血量,应该是进入这个格子本身消耗的血量,加上向右和向下其中需要较少的血量。也就是hpMatirix[i][j] = -matrix[i][j] + min(hpMatirx[i][j + 1], hpMatrix[i + 1][j])。 以-10这一格为例,进入它会消耗10滴血,它右边的格子需要5滴血,下边的格子需要1滴血,所以向下走,因此进入这一格骑士需要11滴血。
4.最后输出hpMatrix[0][0]。
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        // 获取输入
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        
        int[][] matrix = new int[n][m];
        
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j<m; ++j){
                matrix[i][j] = input.nextInt();
            }
        }
        // 记录从每个位置出发,到达目的地,骑士初始至少要有多少血。
        int[][] hpMatrix = new int[n][m];
        // 先处理目的地
        if (matrix[n - 1][m - 1] <= 0){
            hpMatrix[n - 1][m - 1] = 1 - matrix[n - 1][m - 1];
        } else {
            hpMatrix[n - 1][m - 1] = 1;
        }
        
        // 处理最后一行
        for (int j = m - 2; j >= 0; --j) {
            if (hpMatrix[n - 1][j + 1] - matrix[n - 1][j] > 0){
                hpMatrix[n - 1][j] = hpMatrix[n - 1][j + 1] - matrix[n - 1][j];
            } else {
                hpMatrix[n - 1][j] = 1;
            }
        }
        
        // 处理最后一列
        for (int i = n-2; i >= 0; --i) {
            if (hpMatrix[i + 1][m-1] - matrix[i][m-1] > 0) {
                hpMatrix[i][m - 1] = hpMatrix[i + 1][m-1] - matrix[i][m-1];
            } else {
                hpMatrix[i][m - 1] = 1;
            }
        }
        
        // 从后往前处理剩余位置
        for (int i = n - 2; i >= 0; --i) {
            for (int j = m - 2; j >= 0; --j) {
                // 往右走需要多少血
                int toLeft = hpMatrix[i][j + 1] - matrix[i][j] > 0 ? hpMatrix[i][j + 1] - matrix[i][j] : 1;
                // 往下走需要多少血
                int toDown = hpMatrix[i + 1][j] - matrix[i][j] > 0 ? hpMatrix[i + 1][j] - matrix[i][j] : 1;
                hpMatrix[i][j] = toLeft > toDown ? toDown : toLeft;
            }
        }
        
        System.out.println(hpMatrix[0][0]);
    }
}


发表于 2019-08-12 13:09:33 回复(1)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n,m;
    cin>>n>>m;
    int a[n][m];
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>a[i][j];
    int dp[m+1];
    dp[m] = 1;
    for(int i=m-1;i>=0;i--)
        dp[i] = max(1, dp[i+1]-a[n-1][i]);
    dp[m] = INT_MAX;
    for(int i=n-2;i>=0;i--)
        for(int j=m-1;j>=0;j--)
            dp[j] = max(1, min(dp[j], dp[j+1]) - a[i][j]); 
    cout<<dp[0]<<endl;
    return 0;
}

发表于 2020-03-06 01:40:27 回复(0)
#include <iostream>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    int arr[n][m], dp[n][m];
    for (int i = 0; i < n; ++i) 
        for (int j = 0; j < m; ++j) cin >> arr[i][j];
    // 时间复杂度O(NM),空间复杂度O(NM)
    dp[n - 1][m - 1] = max(1 - arr[n - 1][m - 1], 1);
    for (int i = n - 2; i >= 0; --i) dp[i][m - 1] = max(dp[i + 1][m - 1] - arr[i][m - 1], 1);
    for (int j = m - 2; j >= 0; --j) dp[n - 1][j] = max(dp[n - 1][j + 1] - arr[n - 1][j], 1);
    for (int i = n - 2; i >= 0; --i) {
        for (int j = m - 2; j >= 0; --j) {
            dp[i][j] = min(max(dp[i + 1][j] - arr[i][j], 1), 
                           max(dp[i][j + 1] - arr[i][j], 1));
        }
    }
    cout << dp[0][0];
    return 0;
}

发表于 2022-11-01 11:24:51 回复(0)
n , m = map(int , input().split())
map = []

for i in range(n):
    o = input().split()
    map.append(o)

for i in range(n):
    for j in range(m):
        map[i][j] = int(map[i][j])

for i in range(n-1,-1,-1):
    for j in range(m-1,-1,-1):
        if i == n-1 and j != m-1:
            map[i][j] = map[i][j+1] + map[i][j]
            
        elif i != n-1 and j == m-1:
            map[i][j] = map[i+1][j] + map[i][j]
        
        elif i != n-1 and j != m-1:
            map[i][j] = max(map[i][j+1] + map[i][j] , map[i+1][j] + map[i][j])
        
        if map[i][j] > 0:
            map[i][j] = 0
        
print(1-(map[0][0]))

发表于 2023-04-20 19:28:38 回复(0)
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;

// dp[i][j]: 从 i,j 位置进入需要拥有的血量
// dp[i][j]=max{1,min{dp[i+1][j]-a[i][j],dp[i][j+1]-a[i][j]}}
// dp[n-1][m-1]=max{1,1-a[n-1][m-1]}
// dp[x][y]=INF if x>=n&nbs***bsp;y>=m

int a[1009][1009];
int n,m;
int dp(int i,int j){
  if(i>=n||j>=m) return INF;
  if(i==n-1&&j==m-1) return max(1,1-a[n-1][m-1]);
  static int cache[1009][1009];
  if(cache[i][j]==0){
    cache[i][j]=max(1,min(dp(i+1,j)-a[i][j],dp(i,j+1)-a[i][j]));
  }
  return cache[i][j];
}

int main(){
  cin>>n>>m;
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      cin>>a[i][j];
    }
  }
  cout<<dp(0,0)<<endl;
}

发表于 2022-08-28 12:03:39 回复(0)
def solution(nums, n, m):
    dp = [[0 for j in range(m)] for i in range(n)]
    dp[-1][-1] = max(1, 1 - nums[n - 1][-1])
    for i in range(2, n + 1):
        dp[-i][m - 1] = max(1, dp[-i + 1][m - 1] - nums[-i][m - 1])
    for j in range(2, m + 1):
        dp[n - 1][-j] = max(1, dp[n - 1][-j + 1] - nums[n - 1][-j])
    for i in range(2, n + 1):
        for j in range(2, m + 1):
            dp[-i][-j] = max(1, min(dp[-i + 1][-j], dp[-i][-j + 1]) - nums[-i][-j])
    return dp[0][0]


n, m = map(int, input().split())
nums = []
for i in range(n):
    nums.append(list(map(int, input().split())))
res = solution(nums, n, m)
print(res)

发表于 2022-08-17 22:00:55 回复(0)
public static int dp12(int[][] num) {
        int m = num.length, n = num[0].length;
        int[][] dp = new int[m][n];
        dp[m - 1][n - 1] = Math.max(0, 1 - num[m - 1][n - 1]);
        for (int i = m - 2; i >= 0; i--) {
            dp[i][n - 1] = Math.max(0, dp[i + 1][n - 1] - num[i][n - 1]);
        }
        for (int i = n - 2; i >= 0; i--) {
            dp[m - 1][i] = Math.max(0, dp[m - 1][i + 1] - num[m - 1][i]);
        }
        for (int i = m - 2; i >= 0; i--) {
            for (int j = n - 2; j >= 0; j--) {
                int min = Math.min(dp[i][j + 1], dp[i + 1][j]);
                dp[i][j] = Math.max(0, min - num[i][j]);
            }
        }
        return dp[0][0];
    }
发表于 2022-06-30 16:56:37 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int aa = 0;
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            int n = in.nextInt();
            int m = in.nextInt();
            int[][] nums = new int[n][m];
            for(int i=0;i<n;i++) {
                for(int j=0;j<m;j++) {
                    nums[i][j] = in.nextInt(); 
                }
            }
            
            int[][] dp = new int[n+1][m+1];
            dp[n][m] = 1 - nums[n-1][m-1]  <= 0 ? 1 : 1 - nums[n-1][m-1];
            for(int i=n-1;i>0;i--) {
                if(nums[i-1][m-1] > 0) {
                    dp[i][m] = nums[i-1][m-1] - dp[i+1][m] >= 0 ? 1 : dp[i+1][m] - nums[i-1][m-1]; 
                } else if(nums[i-1][m-1] == 0) {
                    dp[i][m] = dp[i+1][m];
                } else {
                    dp[i][m] = -nums[i-1][m-1] + dp[i+1][m];
                }
            }
            
            for(int i=m-1;i>0;i--) {
                if(nums[i-1][m-1] > 0) {
                    dp[n][i] = nums[n-1][i-1] - dp[n][i+1] >= 0 ? 1 :  dp[n][i+1] - nums[n-1][i-1]; 
                }else if(nums[n-1][i-1] == 0) {
                    dp[n][i] = dp[n][i+1];;
                } else {
                    dp[n][i] = -nums[n-1][i-1] + dp[n][i+1];
                }
            }
            
            
            for(int i=n-1;i>0;i--) {
                for(int j=m-1;j>0;j--) {
                    int a = Math.min(dp[i+1][j],dp[i][j+1]);
                    if(nums[i-1][j-1] > 0) {
                        dp[i][j] = nums[i-1][j-1] - a >= 0 ? 1 : a - nums[i-1][j-1]; 
                    } else {
                        dp[i][j] = nums[i-1][j-1] == 0 ? a : -nums[i-1][j-1] + a;
                    }
                }
            }
            
            System.out.println(dp[1][1]);
        }
    }
}

发表于 2022-04-24 23:26:06 回复(0)