第一行输入格子行列数(格式为 M N),第2~M+1行每行输入N个数,作为格子值K,中间以空格分割;0 < M, N < 1000,-100 < K < 100
初始最小行动力
2 3 -2 -3 3 -5 -10 1
6
/ 本题dp可解毫无疑问;本人较懒就用了二分答案+dfs判断的方式。从题意易知起始的大小与路径中最小值最大的情况成正比,故而枚举答案,复杂度O(logn),对于每次枚举判断是否可行,即路径中存在一条路恒>0,复杂度O(n).这样一来综合复杂度O(nlogn),n=1e6,故而可解。 /
int b[1001][1001],a[1001][1001],c[1001][1001],n,m;
void dfs(int x,int y)
{
if(x>n||y>m||a[x][y]<=0||c[x][y])return;
c[x][y]=1;
dfs(x+1,y);
dfs(x,y+1);
}
int main()
{
std::cin>>n>>m;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)std::cin>>b[i][j];
int l=1,r=1e9,mid,g=1e9;
while(l<=r)
{
int mid=(l+r)/2;
std::memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=b[i][j];
a[1][1]+=mid;
for(int i=2;i<=m;i++)a[1][i]+=a[1][i-1];
for(int j=2;j<=n;j++)a[j][1]+=a[j-1][1];
for(int i=2;i<=n;i++)
for(int j=2;j<=m;j++)a[i][j]+=std::max(a[i-1][j],a[i][j-1]);
dfs(1,1);
if(c[n][m])
{
g=std::min(g,mid);
r=mid-1;
}
else l=mid+1;
}
std::cout<<g<<std::endl;
}
import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int m = in.nextInt(); int n = in.nextInt(); int[][] vals = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { vals[i][j] = in.nextInt(); } } int[][] dp = new int[m+1][n+1]; for (int i = m-1; i >= 0; i--) { for (int j = n-1; j >= 0; j--) { dp[i][j] = Math.min(Math.max(1, dp[i+1][j]), Math.max(1, dp[i][j+1])) - vals[i][j]; } } dp[0][0] = dp[0][0] > 0 ? dp[0][0] : 1; System.out.println(dp[0][0]); } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @author wylu */ public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] strs = br.readLine().split(" "); int m = Integer.parseInt(strs[0]), n = Integer.parseInt(strs[1]); int[][] grid = new int[m][n]; for (int i = 0; i < m; i++) { strs = br.readLine().split(" "); for (int j = 0; j < n; j++) { grid[i][j] = Integer.parseInt(strs[j]); } } int[][] dp = new int[m + 1][n + 1]; dp[m][n] = 1; for (int i = m - 1; i >= 0; i--) { for (int j = n - 1; j >= 0; j--) { dp[i][j] = Math.max(1, Math.min(dp[i + 1][j], dp[i][j + 1]) - grid[i][j]); } } System.out.println(dp[0][0]); } }
【关键点】角色的三种状态:
角色在(i, j)之前(即在(i-1, j)或者(i, j-1),下一步即将移动到(i, j))行动力用dp[i][j]表示,比如初始行动力为dp[0][0],下一步即将移动到(0, 0);
角色在(i, j)时(下一步即将移动到(i+1, j)或者(i, j+1))行动力等于dp[i][j]+a[i][j],比如初始行动力为dp[0][0],角色在(0, 0)时行动力为dp[0][0]+a[0][0];
角色在(i, j)之后(即在(i+1, j)或者(i, j+1),上一步在(i, j)),此时有min(dp[i+1][j], dp[i][j+1])等于dp[i][j]+a[i][j]。
【分析】dp[i][j]表示角色尚在格子(i, j)之前并且即将要移动到格子(i, j)时的行动力。
dp[0][0]表示初始的行动力。
当行动力小于或者等于0时游戏失败,dp[i][j]必然大于或者等于(对应递推公式的max)1,即dp[i][j]>=1。
dp[i][j]+a[i][j]表示角色在格子(i, j)但尚未往下移动时的行动力,此时行动力为min(dp[i+1][j], dp[i][j+1]),采用min是因为最后要求的是最小值。
最后求解初始时刻的行动力,则应该从后往前推理,可得,
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int m,n; cin>>m>>n; vector<vector<int> > a(m,vector<int>(n,0)); vector<vector<int> > dp(m+1,vector<int>(n+1,0)); for(int i=0;i<m;++i) for(int j=0;j<n;++j) cin>>a[i][j]; for(int i=m-1;i>=0;--i) for(int j=n-1;j>=0;--j) dp[i][j]=max(1,min(dp[i+1][j],dp[i][j+1])-a[i][j]); cout<<dp[0][0]<<endl; return 0; }
#写一个python版的答案 #读取数据 m,n = map(int,input().split()) array = [] for _ in range(m): list1 = list(map(int,input().split())) array.append(list1) #构建一个辅助数组,记录移动方向 #1表示竖直移动,0表示水平移动 line = [[0]*n for _ in range(m)] for j in range(n-1): array[0][j+1] += array[0][j] for i in range(m-1): array[i+1][0] += array[i][0] #动态规划算每个点最小的体力值 for i in range(1,m): for j in range(1,n): if(array[i-1][j] > array[i][j-1]): array[i][j] += array[i-1][j] line[i][j] = 1 else: array[i][j] += array[i][j-1] #print(array) #从右下角 往 左上角 回溯。 求得最小值 list1 = [] i = m-1 j = n-1 while(i>0 and j>0): if(line[i][j] == 1): i -= 1 else: j -= 1 list1.append(array[i][j]) if(i>0): for k in range( i): list1.append(array[k][0]) else: for k in range( j): list1.append(array[0][k]) #print(list1) res = min(list1) print(max(-res+1,1))
#include <iostream> #include <unordered_map> #include <unordered_set> #include <vector> #include <queue> #include <map> #include <set> #include <stack> #include <sstream> #include <stdlib.h> #include <algorithm> #include <limits.h> #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) #define ll long long using namespace std; int main() { int m, n; scanf("%d%d", &m, &n); vector<vector<int>> nums(m + 1, vector<int>(n + 1, 0)), v(m + 1, vector<int>(n + 1, 0)), dp(m + 1, vector<int>(n + 1, 1)); for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) scanf("%d", &nums[i][j]); for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) { if (i == 1 || j == 1) { if (i == 1) { dp[i][j] = max(dp[i][j - 1], -(v[i][j - 1] + nums[i][j]) + 1); v[i][j] = v[i][j - 1] + nums[i][j]; } else { dp[i][j] = max(dp[i - 1][j], -(v[i - 1][j] + nums[i][j]) + 1); v[i][j] = v[i - 1][j] + nums[i][j]; } } else { dp[i][j] = min(max(dp[i][j - 1], -(v[i][j - 1] + nums[i][j]) + 1), max(dp[i - 1][j], -(v[i - 1][j] + nums[i][j]) + 1)); v[i][j] = max(v[i][j - 1] + nums[i][j], v[i - 1][j] + nums[i][j]); } //cout << i << " " << j << " " << dp[i][j] << endl; } printf("%d\n", dp[m][n]); return 0; }提供两组不能通过的测试用例:
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); while(sc.hasNextInt()){ int n = sc.nextInt(); int m = sc.nextInt(); int[][] arr = new int[n][m]; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ arr[i][j]=sc.nextInt(); } } int[][] dp = new int[n][m]; dp[n-1][m-1]=1; for(int i=n-2;i>=0;i--){ dp[i][m-1]=Math.max(1,dp[i+1][m-1]-arr[i][m-1]); } for(int i=m-2;i>=0;i--){ dp[n-1][i]=Math.max(1,dp[n-1][i+1]-arr[n-1][i]); } for(int i=n-2;i>=0;i--){ for(int j=m-2;j>=0;j--){ dp[i][j]=Math.max(1,Math.min(dp[i+1][j],dp[i][j+1])-arr[i][j]); } } System.out.println(dp[0][0]); } } }思路就是动态规划,不过是从右下角倒着往前更新dp数组,计算到达每个格子之前,需要的最小行动力,保证到达每个格子之前行动力都至少为1.
#include<iostream> using namespace std; const int N = 1010, M = 1010; int a[N][M], dp[N][M]; int n,m; int main() { cin >> n >> m; for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j) cin >> a[i][j]; for(int i = n - 1; i >= 0; --i) for(int j = m - 1; j >= 0; --j) dp[i][j]= min(max(1,dp[i+1][j]-a[i][j]),max(dp[i][j+1]-a[i][j],1)); cout << dp[0][0] << endl; return 0; }
import sys class Solution(object): def solveGrid(self,grid): self.M = len(grid) - 1 self.N = len(grid[0]) - 1 self.dp = [[sys.maxint for j in range(self.N+1)] for i in range(self.M+1)] self.countPaths(grid, 1, 1, 1, []) return self.dp[self.M][self.N] def countPaths(self, grid, row, col, level, path): if path: path.append(path[-1] + grid[row][col]) else: path.append(grid[row][col]) tmp = max(1, -min(path) + 1) self.dp[row][col] = min(self.dp[row][col], tmp) if row == self.M and col == self.N: return if col+1<=self.N \ and tmp == self.dp[row][col] \ and self.dp[row][col] < self.dp[row][col+1] \ and self.dp[row][col] < self.dp[self.M][self.N]: self.countPaths(grid,row,col+1, level+1, path) path.pop() if row+1<=self.M \ and tmp == self.dp[row][col] \ and self.dp[row][col] < self.dp[row+1][col] \ and self.dp[row][col] < self.dp[self.M][self.N]: self.countPaths(grid,row+1,col, level+1, path) path.pop() if __name__ == "__main__": line = raw_input() lines = line.split() M, N = int(lines[0]), int(lines[1]) grid = [] grid.append([0 for j in range(N+1)]) for _ in xrange(M): line = raw_input() lines = line.split() tmp = [0] + [int(item) for item in lines] grid.append(tmp) s = Solution() print s.solveGrid(grid)递归 加 剪枝 即可求解
A到吐血 #include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> using namespace std; int n,m; int grid[1000][1000]; int ans; void dfs(int x,int y,int temp,int w) { if (x<0||x>=m||y<0||y>=n) { return ; } if (y==n-1&&x==m-1) { temp=min(temp,w+grid[y][x]+temp); ans=max(temp,ans); return ; } else if (temp>ans) { int res1=w+grid[y][x]; int res=temp; if (res1<=0) { res+=res1; res1=0; } //int res=min(temp,res1); dfs(x+1,y,res,res1); dfs(x,y+1,res,res1); } } int main() { while (cin>>n>>m) { for (int i=0;i<n;i++) { for (int j=0;j<m;j++) { scanf("%d",&grid[i][j]); } } ans=-100000000; int temp=grid[0][0]; dfs(0,0,0,0); //dfs(0,0,0,temp); cout<<abs(ans)+1<<endl; } return 0; }