POJ 1163 The Triangle 典型的递归问题

题意:寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。

解题思路:
二维数组存放数字三角形;
D[r][j]:第 r 行第 j 个数字(r,j 从 1 开始);
MaxSum(r,j):从 D(r,j)到底边的各条路径中,最佳路径的数字之和。
问题:求 MaxSum(1,1)。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {

    private static final int MAX = 101;
    private static int D[][] = new int[MAX][MAX];
    private static int maxSum[][] = new int[MAX][MAX];
    private static int N;

//  /**
//   * 超时代码,因为有大量的重复计算。时间复杂度:2^n
//   */
//  private static int MaxSum(int i, int j) {
//      if (i == N) {
//          return D[i][j];
//      }
//      int x = MaxSum(i + 1, j);
//      int y = MaxSum(i + 1, j + 1);
//      return Math.max(x, y) + D[i][j];
//  }

    /**
     * 记忆递归型动归程序,时间复杂度:n^2
     * 每算出一个 MaxSum(r,j) 就保存起来,下次用到其值时,直接取用,则可以避免重复计算
     */
    private static int MaxSum(int i, int j) {
        if (maxSum[i][j] != 0) {
            return maxSum[i][j];
        }
        if (i == N) {
            maxSum[i][j] = D[i][j];
        } else {
            int x = MaxSum(i + 1, j);
            int y = MaxSum(i + 1, j + 1);
            maxSum[i][j] = Math.max(x, y) + D[i][j];
        }
        return maxSum[i][j];
    }

    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        while (in.nextToken() != StreamTokenizer.TT_EOF) {
            N = (int) in.nval;
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= i; j++) {
                    in.nextToken();
                    D[i][j] = (int) in.nval;
                }
            }
            out.println(MaxSum(1, 1));
        }
        out.flush();
    }
}

以下为优化方案:

优化:将递归转换为递推!!!
这里写图片描述

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {

    private static final int MAX = 101;
    private static int D[][] = new int[MAX][MAX];
    private static int maxSum[][] = new int[MAX][MAX];
    private static int N;
    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        while (in.nextToken() != StreamTokenizer.TT_EOF) {
            N = (int) in.nval;
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= i; j++) {
                    in.nextToken();
                    D[i][j] = (int) in.nval;
                }
            }
            System.arraycopy(D[N], 1, maxSum[N], 1, N);
            for (int i = N - 1; i >= 1; i--) {
                for (int j = 1; j <= i; j++) {
                    maxSum[i][j] = Math.max(maxSum[i + 1][j], maxSum[i + 1][j + 1]) + D[i][j];
                }
            }
            out.println(maxSum[1][1]);
        }
        out.flush();
    }
}

进一步优化:空间优化
没必要用二维 maxSum 数组存放每一个 MaxSum(r,j),只要从底层一行行向上递推,那么只要一堆数组 maxSum[100] 即可,即只要存储一行的 MaxSum 值就可以。

更进一步优化:空间优化
进一步考虑,连 maxSum 数组都可以不要,直接用 D 的第 n 行代替 maxSum 即可。节省空间,时间复杂度不变。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {

    private static final int MAX = 101;
    private static int D[][] = new int[MAX][MAX];
    private static int maxSum[];
    private static int N;

    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        while (in.nextToken() != StreamTokenizer.TT_EOF) {
            N = (int) in.nval;
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= i; j++) {
                    in.nextToken();
                    D[i][j] = (int) in.nval;
                }
            }
            maxSum = D[N]; // maxSum 指向第 n 行
            for (int i = N - 1; i >= 1; i--) {
                for (int j = 1; j <= i; j++) {
                    maxSum[j] = Math.max(maxSum[j], maxSum[j + 1]) + D[i][j];
                }
            }
            out.println(maxSum[1]);
        }
        out.flush();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值