解题思路:
首先要知道最后的结果在最后一行中间产生,为什么?左右移的差不会超过1
向左走多少就会尽可能向右走多少。
若N为奇数,肯定落在n/2+1的位置
若N为偶数,则结果应该是max(n/2,n/2+1)
第一步:画搜索树

第二步:暴力DFS
我们可以根据N的奇偶确定递归的终点,
若n为奇,则终点就是(n,n/2+1),即(5,3)对应2这个数字
若为偶,则终点为max((n,n/2),(n,n/2+1)) 以n为4为例,则对应7或4
递归公式:dfs(x,y)=max(dfs(x-1,y),dfs(x-1,y-1))+arr[x][y]
递归边界:x<1||y<1,dfs(x,y)=0
参考代码:
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
static long [][]arr;
public static void main(String[] args) throws IOException {
int n=Integer.parseInt(br.readLine());
arr=new long[n+2][n+2];
String []s;
for(int i=1;i<=n;i++){
s=br.readLine().split(" ");
for(int j=1;j<=i;j++){
arr[i][j]=Long.parseLong(s[j-1]);
}
}
long result=0;
if(n%2!=0){
result=dfs(n,n/2+1);
}else{
result=dfs(n,n/2)>dfs(n,n/2+1)?dfs(n,n/2):dfs(n,n/2+1);
}
pw.println(result);
pw.flush();
}
private static long dfs(int x,int y){
if(x<1||y<1){
return 0;
}
return Math.max(dfs(x-1,y-1),dfs(x-1,y))+arr[x][y];运行结果:时间超限: 55 分
第三步:记忆化搜索
考虑到搜索树里,蓝色框中的dfs(x,y)在左支中已经计算过,无需重复递归,记录左支的结果
参考代码:
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
static long [][]arr;
static long [][]map;
public static void main(String[] args) throws IOException {
int n=Integer.parseInt(br.readLine());
arr=new long[n+2][n+2];
map=new long[n+1][n+1];
String []s;
for(int i=1;i<=n;i++){
s=br.readLine().split(" ");
for(int j=1;j<=i;j++){
arr[i][j]=Long.parseLong(s[j-1]);
}
}
long result=0;
if(n%2!=0){
result=dfs(n,n/2+1);
}else{
result=dfs(n,n/2)>dfs(n,n/2+1)?dfs(n,n/2):dfs(n,n/2+1);
}
pw.println(result);
pw.flush();
}
private static long dfs(int x,int y){
if(map[x][y]!=0){
return map[x][y];
}
long sum=0;
if(x<1||y<1){
sum= 0;
}else{
sum=Math.max(dfs(x-1,y-1),dfs(x-1,y))+arr[x][y];
}
map[x][y]=sum;
return sum;
}
}运行结果:时间超限: 64 分
没关系,继续优化
第四步:递推
递推公式:dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+arr[i][j]
参考代码:
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
static long [][]arr;
static long [][]dp;
public static void main(String[] args) throws IOException {
int n=Integer.parseInt(br.readLine());
arr=new long[n+2][n+2];
dp=new long[n+1][n+1];
String []s;
for(int i=1;i<=n;i++){
s=br.readLine().split(" ");
for(int j=1;j<=i;j++){
arr[i][j]=Long.parseLong(s[j-1]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-1])+arr[i][j];
}
}
if(n%2!=0){
pw.println(dp[n][n/2+1]);
}else{
pw.println(dp[n][n/2]>dp[n][n/2+1]?dp[n][n/2]:dp[n][n/2+1]);
}
pw.flush();
}
}运行结果:100分 运行时间: 490ms 消耗内存: 15616KB
继续优化,二维dp→一维dp
因为dp[i][j]肯定是从i-1转换来的,所以不需要管行变化
dp[j]=max(dp[j],dp[j-1])+arr[i][j]
参考代码:
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
static long [][]arr;
static long []dp;
public static void main(String[] args) throws IOException {
int n=Integer.parseInt(br.readLine());
arr=new long[n+2][n+2];
dp=new long[n+1];
String []s;
for(int i=1;i<=n;i++){
s=br.readLine().split(" ");
for(int j=1;j<=i;j++){
arr[i][j]=Long.parseLong(s[j-1]);
}
}
for(int i=1;i<=n;i++){
for(int j=i;j>=1;j--){
dp[j]=Math.max(dp[j],dp[j-1])+arr[i][j];
}
}
if(n%2!=0){
pw.println(dp[n/2+1]);
}else{
pw.println(dp[n/2]>dp[n/2+1]?dp[n/2]:dp[n/2+1]);
}
pw.flush();
}
}运行结果:100分 运行时间: 583ms 消耗内存: 15504KB
注意事项:
j应该倒着遍历,即从每一行的最后一个数字向前遍历
为什么?如果正着遍历,那么dp[j]会记录这次的结果作为j+1的dp[j-1]
例如i=2时,
j=1时,dp[1]=dp[1]+arr[2][1]=10
j=2时,dp[2]=dp[1]+arr[2][2]=10+8=18
但是其实dp[2]应该等于7+8=15
所以j不应该从1开始,而是从j=i开始向前遍历
参考代码:
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复