【蓝桥杯】动态规划(dp)入门!| 入门动态规划的正确方式! ——学习笔记

目录

最暴力的dfs --> 记忆化搜索 ---> 递推(dp)

记忆化搜索 = 暴力dfs + 记录答案

递推的公式 = dfs 向下递归的公式

递推数组的初始值 = 递归的边界

动态规划(dp)入门 | 这tm才是入门动态规划的正确方式! | dfs记忆化搜索 | 全体起立!!_哔哩哔哩_bilibili 大佬教学视频,非常细!

 题目一:大盗阿福 

题目描述

输入格式输入的第一行是一个整数 T,表示一共有 T 组数据。接下来的每组数据,第一行是一个整数 N ,表示一共有 N 家店铺。第二行是 N 个被空格分开的正整数,表示每一家店铺中的现金数量。每家店铺中的现金数量均不超过1000。

输出格式对于每组数据,输出一行。该行包含一个整数,表示阿福在不惊动警察的情况下可以得到的现金数量。

 题目分析

题目代码1——最暴力的dfs 

题目代码 2——记忆化搜索模板

记忆化搜索 = 暴力dfs + 记录答案

题目代码3——递推(dp)

递推的公式 = dfs 向下递归的公式递推数组的初始值 = 递归的边界

 题目代码4——递推(dp)

空间优化

第二题:数字三角形 

输入格式

输出格式

输入输出样例

说明/提示

题目代码1——最暴力的dfs 

题目代码 2——记忆化搜索模板

记忆化搜索 = 暴力dfs + 记录答案

题目代码3——递推(dp)

递推的公式 = dfs 向下递归的公式递推数组的初始值 = 递归的边界

 第三题:01背包问题

题目代码1——最暴力的dfs 

题目代码 2——记忆化搜索模板

记忆化搜索 = 暴力dfs + 记录答案

题目代码3——递推(dp)

递推的公式 = dfs 向下递归的公式递推数组的初始值 = 递归的边界


 

最暴力的dfs --> 记忆化搜索 ---> 递推(dp)


记忆化搜索 = 暴力dfs + 记录答案


递推的公式 = dfs 向下递归的公式


递推数组的初始值 = 递归的边界

动态规划(dp)入门 | 这tm才是入门动态规划的正确方式! | dfs记忆化搜索 | 全体起立!!_哔哩哔哩_bilibili 大佬教学视频,非常细!

 题目一:大盗阿福 

题目描述

阿福是一名经验丰富的大盗。趁着月黑风高,阿福打算今晚洗劫一条街上的店铺。

这条街上一共有 N 家店铺,每家店中都有一些现金。

阿福事先调查得知,只有当他同时洗劫了两家相邻的店铺时,街上的报警系统才会启动,然后警察就会蜂拥而至。

作为一向谨慎作案的大盗,阿福不愿意冒着被警察追捕的风险行窃。

他想知道,在不惊动警察的情况下,他今晚最多可以得到多少现金?

输入格式
输入的第一行是一个整数 T,表示一共有 T 组数据。
接下来的每组数据,第一行是一个整数 N ,表示一共有 N 家店铺。
第二行是 N 个被空格分开的正整数,表示每一家店铺中的现金数量。每家店铺中的现金数量均不超过1000。

输出格式
对于每组数据,输出一行。该行包含一个整数,表示阿福在不惊动警察的情况下可以得到的现金数量。

输入样例
2
3
1 8 2
4
10 7 6 14

输出样例
8
24

数据范围
T ≤ 50
1 ≤ N ≤ 105

提示
对于第一组样例,阿福选择第 2 家店铺行窃,获得的现金数量为 8。
对于第二组样例,阿福选择第 1 和 4 家店铺行窃,获得的现金数量为 10 + 14 = 24。

 题目分析

最暴力的dfs --> 记忆化搜索 ---> 递推(dp)

题目代码1——最暴力的dfs 

import java.util.Arrays;
import java.util.Scanner;

public class 大盗阿福_dp {
    static int t, n;
    static int arr[] = new int[106];
    static int mem[] = new int[106];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        t = sca.nextInt();

        while (t-- > 0) {
            n = sca.nextInt();
            for (int i = 1; i <= n; i++) {
                arr[i] = sca.nextInt();
            }
            System.out.println(dfs(1));
        }
    }

    static int dfs(int x) {//x:表示当前正在考虑哪家店

        if (x > n) return  0;
        else return Math.max(dfs(x + 1), dfs(x + 2) + arr[x]);
    }
}

题目代码 2——记忆化搜索模板

记忆化搜索 = 暴力dfs + 记录答案

import java.util.Arrays;
import java.util.Scanner;

public class 大盗阿福_dp {
    static int t, n;
    static int arr[] = new int[106];
    static int mem[] = new int[106];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        t = sca.nextInt();

        while (t-- > 0) {
            n = sca.nextInt();
            for (int i = 1; i <= n; i++) {
                arr[i] = sca.nextInt();
            }
            Arrays.fill(mem,0);//每一组记忆化前都要赋值为0
            System.out.println(dfs(1));
        }
    }
    //mem[i]存的是从第i家店铺开始(i~n)能洗劫到的最大价值
    static int dfs(int x) {
        if (mem[x] != 0) return mem[x];//记忆化搜索

        int sum = 0;
        if (x > n) sum = 0;
        else sum = Math.max(dfs(x + 1), dfs(x + 2) + arr[x]);

        mem[x] = sum;
        return sum;
    }
}

题目代码3——递推(dp)

递推的公式 = dfs 向下递归的公式
递推数组的初始值 = 递归的边界

import java.util.Arrays;
import java.util.Scanner;

public class 大盗阿福_dp {
    static int t, n;
    static int arr[] = new int[106];
    static int mem[] = new int[106];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        t = sca.nextInt();

        while (t-- > 0) {
            n = sca.nextInt();
            for (int i = 1; i <= n; i++) {
                arr[i] = sca.nextInt();
            }
            for (int i = n; i > 0; i--) {
              mem[i] = Math.max(mem[i+1], mem[i+2] + arr[i]);
            }
            System.out.println(mem[1]);
        }
    }
}

 题目代码4——递推(dp)

空间优化

import java.util.Arrays;
import java.util.Scanner;

public class 大盗阿福_dp {
    static int t, n;
    static int arr[] = new int[106];
    static int mem[] = new int[106];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        t = sca.nextInt();

        while (t-- > 0) {
            n = sca.nextInt();
            for (int i = 1; i <= n; i++) {
                arr[i] = sca.nextInt();
            }
            int sum=0, temp1 = 0, temp2 = 0;
            for (int i = 1; i <=n; i++) {
                sum = Math.max(temp1, temp2 + arr[i]);
                temp2 = temp1;
                temp1 = sum;
            }
            System.out.println(sum);
        }
    }
}

第二题:数字三角形 

观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

        7 
      3   8 
    8   1   0 
  2   7   4   4 
4   5   2   6   5 

在上面的样例中,从 7→3→8→7→5 的路径产生了最大

输入格式

第一个行一个正整数 r ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

输出格式

单独的一行,包含那个可能得到的最大的和。

输入输出样例

输入 #1复制

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5 

输出 #1复制

30

说明/提示

【数据范围】
对于 100% 的数据,1≤r≤1000,所有输入在[0,100] 范围内。

题目代码1——最暴力的dfs 

import java.util.Scanner;

public class 数字三角形_dp1 {
    static int n;
    static int map[][];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        n = sca.nextInt();
        map = new int[n + 1][n + 1];

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                map[i][j] = sca.nextInt();
            }
        }
        System.out.println(dfs(1, 1));
    }

    static int dfs(int x, int y) {
        if (x > n || y > n) return 0;
        else return Math.max(dfs(x + 1, y), dfs(x + 1, y + 1)) + map[x][y];
    }
}

题目代码 2——记忆化搜索模板

记忆化搜索 = 暴力dfs + 记录答案

import java.util.Scanner;

public class 数字三角形_dp1 {
    static int n;
    static int map[][];
    static int mem[][];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        n = sca.nextInt();
        map = new int[1005][1005];
        mem = new int[1005][1005];

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                map[i][j] = sca.nextInt();
            }
        }
        System.out.println(dfs(1, 1));
    }

    static int dfs(int x, int y) {
        if (mem[x][y] > 0) return mem[x][y];

        int sum = 0;
        if (x > n || y > n) sum = 0;
        else sum = Math.max(dfs(x + 1, y), dfs(x + 1, y + 1)) + map[x][y];
        mem[x][y] = sum;
        return sum;
    }
}

题目代码3——递推(dp)

递推的公式 = dfs 向下递归的公式
递推数组的初始值 = 递归的边界

import java.util.Scanner;

public class 数字三角形_dp2 {
    static int n;
    static int map[][];
    static int dp[][];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        n = sca.nextInt();
        map = new int[1005][1005];
        dp = new int[1005][1005];

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                map[i][j] = sca.nextInt();
            }
        }
        for (int i = n; i >= 1; i--) {//反着推
            for (int j = 1; j <= n; j++) {//j是从1开始
                dp[i][j] = Math.max(dp[i + 1][j], dp[i + 1][j + 1]) + map[i][j];
            }
        }
        System.out.println(dp[1][1]);
    }
}

 第三题:01背包问题

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 0

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

题目代码1——最暴力的dfs 

import java.util.Scanner;

public class _01背包问题_dp1 {
    static int n, m,res=0;
    static int v[] = new int[1005];
    static int w[] = new int[1005];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        n = sca.nextInt();
        m = sca.nextInt();
        for (int i = 1; i <= n; i++) {
            v[i] = sca.nextInt();
            w[i] = sca.nextInt();
        }
       res = dfs(1, m);
        System.out.println(res);
    }

    static int dfs(int x, int spV) {//x表示当前考虑第几个物品,spV表示当前剩余的背包体积
        if (x > n) return 0;

        //剩余背包体积不够放当前物品时只能不选,考虑下一个物品
        if (spV < v[x]) return dfs(x + 1, spV);
        else if (spV >= v[x]) {//当背包剩余体积 > 当前物品体积时 有俩种选择 选/不选
            return Math.max(dfs(x + 1, spV), dfs(x + 1, spV - v[x]) + w[x]);
        }
        return 0;
    }

}

题目代码 2——记忆化搜索模板

记忆化搜索 = 暴力dfs + 记录答案

import java.util.Scanner;

public class _01背包问题_dp2 {
    static int n, m, res = 0;
    static int v[] = new int[1005];
    static int w[] = new int[1005];
    static int mem[][] = new int[1005][1005];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        n = sca.nextInt();
        m = sca.nextInt();
        for (int i = 1; i <= n; i++) {
            v[i] = sca.nextInt();
            w[i] = sca.nextInt();
        }
        res = dfs(1, m);
        System.out.println(res);
    }

    static int dfs(int x, int spV) {//x表示当前考虑第几个物品,spV表示当前剩余的背包体积
        if (mem[x][spV] != 0) return mem[x][spV];

        int sum = 0;
        if (x > n) sum = 0;
        //剩余背包体积不够放当前物品时只能不选,考虑下一个物品
        else if (spV < v[x]) sum = dfs(x + 1, spV);
        else if (spV >= v[x]) {//当背包剩余体积 > 当前物品体积时 有俩种选择 选/不选
             sum = Math.max(dfs(x + 1, spV), dfs(x + 1, spV - v[x]) + w[x]);
        }
        mem[x][spV] = sum;
        return sum;
    }
}

题目代码3——递推(dp)

递推的公式 = dfs 向下递归的公式
递推数组的初始值 = 递归的边界

import java.util.Scanner;

public class _01背包问题_dp3 {
    static int n, m, res = 0;
    static int v[] = new int[1005];
    static int w[] = new int[1005];
    static int dp[][] = new int[1005][1005];

    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        n = sca.nextInt();
        m = sca.nextInt();
        for (int i = 1; i <= n; i++) {
            v[i] = sca.nextInt();
            w[i] = sca.nextInt();
        }
        //从下往上推
        for (int i = n; i >= 1; i--) {//i代表背包
            for (int j = 0; j <= m; j++) {//j代码背包体积
                if (j < v[i]) {//如果背包不够装
                    dp[i][j] = dp[i + 1][j];
                } else if (j >= v[i]) {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i + 1][j - v[i]] + w[i]);
                }
            }
        }
        System.out.println(dp[1][m]);
    }
}

你可能感兴趣的:(蓝桥杯,蓝桥杯,动态规划,java,学习,算法)