杨雨彤


私信TA

用户名:dotcpp0724648

访问量:2218

签 名:

菜鸡也会想变强啊

等  级
排  名 4949
经  验 1615
参赛次数 0
文章发表 20
年  龄 21
在职情况 学生
学  校 大庆师范学院
专  业 软件工程

  自我简介:

解题思路:

首先要知道最后的结果在最后一行中间产生,为什么?左右移的差不会超过1

向左走多少就会尽可能向右走多少。

若N为奇数,肯定落在n/2+1的位置

若N为偶数,则结果应该是max(n/2,n/2+1)

第一步:画搜索树




屏幕截图 2024-02-20 131906.png




第二步:暴力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 人评分

  评论区

  • «
  • »