【算法随笔】记忆化搜索

由 MisakaStone 发布

记忆化搜索可以减少重复计算。

以斐波那契数列为例,简单的递归函数存在大量重复计算,时间复杂度较高,因此可以采用记忆化搜索的算法来提高计算效率。

$ F(0)=1 $
$ F(1)=1 $
$ F(2)=F(1)+F(0) $
$ F(3)=F(2)+F(1) $
$ ... $
$ F(n)=F(n-1)+F(n-2) $

代码如下

Scanner keyboard = new Scanner(System.in);
int n = keyboard.nextInt();
keyboard.close();

int[] memorization = new int[n+1];
for (int i = 0; i <= n; i ++) {
    if (i == 0 || i == 1) {
        memorization[i] = 1;
    } else {
        memorization[i] = memorization[i-1] + memorization[i-2];
    }
}

System.out.println(memorization[n]);

例1 Function

题目来源:P1464 Function - 洛谷

题目描述

对于一个递归函数 $w(a,b,c)$

  • 如果 $a \le 0$ 或 $b \le 0$ 或 $c \le 0$ 就返回值$1$。
  • 如果 $a>20$ 或 $b>20$ 或 $c>20$ 就返回 $w(20,20,20)$
  • 如果 $a<b$ 并且 $b<c$ 就返回$ w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)$。
  • 其它的情况就返回 $w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)$

这是个简单的递归函数,但实现起来可能会有些问题。当 $a,b,c$ 均为 $15$ 时,调用的次数将非常的多。你要想个办法才行。

注意:例如 $w(30,-1,0)$ 又满足条件 $1$ 又满足条件 $2$,请按照最上面的条件来算,答案为 $1$。

输入格式

会有若干行。

并以 $-1,-1,-1$ 结束。

保证输入的数在 $[-9223372036854775808,9223372036854775807]$ 之间,并且是整数。

输出格式

输出若干行,每一行格式:

w(a, b, c) = ans

注意空格。

样例 #1

样例输入 #1

1 1 1
2 2 2
-1 -1 -1

样例输出 #1

w(1, 1, 1) = 2
w(2, 2, 2) = 4

题解

import java.util.Scanner;

public class Main {

    static int[][][] w = new int[21][21][21];

    public static void main(String[] args) {

        init();

        Scanner keyboard = new Scanner(System.in);

        int a = keyboard.nextInt();
        int b = keyboard.nextInt();
        int c = keyboard.nextInt();

        while (!(a == b && b == c && a == -1)) {
            if (a < 0 || b < 0 || c < 0) {
                System.out.printf("w(%d, %d, %d) = %d%n", a, b, c, 1);
            } else if (a > 20 || b > 20 || c > 20) {
                System.out.printf("w(%d, %d, %d) = %d%n", a, b, c, w[20][20][20]);
            } else {
                System.out.printf("w(%d, %d, %d) = %d%n", a, b, c, w[a][b][c]);
            }
            a = keyboard.nextInt();
            b = keyboard.nextInt();
            c = keyboard.nextInt();
        }

        keyboard.close();

    }

    public static void init() {

        for (int a = 0; a <= 20; a ++) {
            for (int b = 0; b <= 20; b ++) {
                for (int c = 0; c <= 20; c ++) {
                    if (a == 0 || b == 0 || c == 0) {
                        w[a][b][c] = 1;
                    } else if (a < b && b < c) {
                        w[a][b][c] = w[a][b][c-1] + w[a][b-1][c-1] - w[a][b-1][c];
                    } else {
                        w[a][b][c] = w[a-1][b][c] + w[a-1][b-1][c] + w[a-1][b][c-1] - w[a-1][b-1][c-1];
                    }
                }
            }
        }

    }

}

暂无评论

发表评论