(A卷,100分)- 最大报酬(Java & JS & Python)

题目描述

小明每周上班都会拿到自己的工作清单,工作清单内包含 n 项工作,每项工作都有对应的耗时时间(单位 h)和报酬,工作的总报酬为所有已完成工作的报酬之和,那么请你帮小明安排一下工作,保证小明在指定的工作时间内工作收入最大化。

输入描述

输入的第一行为两个正整数 T,n。
T 代表工作时长(单位 h, 0 < T < 1000000),
n 代表工作数量( 1 < n ≤ 3000)。
接下来是 n 行,每行包含两个整数 t,w。
t 代表该工作消耗的时长(单位 h, t > 0),w 代表该项工作的报酬。

输出描述

输出小明指定工作时长内工作可获得的最大报酬。

用例

输入 40 3
20 10
20 20
20 5
输出 30
说明

题目解析

本题是01背包问题。可以使用动态规划求解。关于01背包问题请先看下面这个博客

本题中

  • 工作时长T相当于背包承重
  • 每一项工作相当于每件物品
  1. 工作消耗的时长相当于物品重量
  2. 工作的报酬相当于物品的价值

01背包二维数组解法(100%)

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
let T, n;
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 1) {
    [T, n] = lines[0].split(" ").map(Number);
  }

  if (n && lines.length === n + 1) {
    lines.shift();
    const tws = lines.map((line) => line.split(" ").map(Number));
    console.log(getResult(T, tws));
    lines.length = 0;
  }
});

/**
 *
 * @param {*} T 工作时长
 * @param {*} tws 数组,元素是tw,也是数组,含义为[该工作消耗的时长, 该项工作的报酬]
 */
function getResult(T, tws) {
  const maxI = tws.length + 1;
  const maxJ = T + 1;
  const dp = new Array(maxI).fill(0).map(() => new Array(maxJ).fill(0)); // 默认将dp数组元素全部初始化为0

  for (let i = 0; i < maxI; i++) {
    for (let j = 0; j < maxJ; j++) {
      if (i === 0 || j === 0) continue; // 第0行或第0列最大报酬保持0
      const [t, w] = tws[i - 1]; // 要选择的工作的[权重,价值]
      if (t > j) {
        // 如果要选择的工作的权重 > 当前背包权重,则无法放入背包,最大价值继承自上一行该列值
        dp[i][j] = dp[i - 1][j];
      } else {
        // 如果要选择的工作的权重 <= 当前背包权重
        // 则我们有两种选择
        // 1、不进行该工作,则最大价值继承自上一行该列值
        // 2、进行该工作,则纳入该工作的价值w,加上+ 剩余权重,在不进行该工作的范围内,可得的最大价值dp[i - 1][j - t]
        // 比较两种选择下的最大价值,取最大的
        dp[i][j] = Math.max(dp[i - 1][j], w + dp[i - 1][j - t]);
      }
    }
  }

  return dp.at(-1).at(-1); // 取二维数组最右下角元素作为题解
}

优化后代码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
let T, n;
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 1) {
    [T, n] = lines[0].split(" ").map(Number);
  }

  if (n && lines.length === n + 1) {
    lines.shift();
    const tws = lines.map((line) => line.split(" ").map(Number));
    console.log(getResult(n, T, tws));
    lines.length = 0;
  }
});

/**
 * @param {*} n 工作数量
 * @param {*} T 工作时长
 * @param {*} tws 数组,元素是tw,也是数组,含义为[该工作消耗的时长, 该项工作的报酬]
 */
function getResult(n, T, tws) {
  tws.unshift([0, 0]);
  const dp = new Array(n + 1).fill(0).map(() => new Array(T + 1).fill(0)); // 默认将dp数组元素全部初始化为0

  for (let i = 1; i <= n; i++) {
    const [t, w] = tws[i];
    for (let j = 1; j <= T; j++) {
      if (j < t) {
        // 注意这里j不能从t开始,会遗漏处理j < t的情况
        dp[i][j] = dp[i - 1][j];
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], w + dp[i - 1][j - t]);
      }
    }
  }

  return dp[n][T];
}

Java算法源码

import java.util.*;

public class Main {
    static ArrayList<Integer[]> nodes;

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

        int T = sc.nextInt();
        int n = sc.nextInt();

        Integer[][] tws = new Integer[n][2];
        for (int i = 0; i < n; i++) {
            tws[i][0] = sc.nextInt();
            tws[i][1] = sc.nextInt();
        }

        System.out.println(getResult(T, tws));
    }

    /**
     *
     * @param T 工作时长
     * @param tws 数组,元素是tw,也是数组,含义为[该工作消耗的时长, 该项工作的报酬]
     * @return 最大报酬
     */
    public static int getResult(int T, Integer[][] tws) {
        int maxI = tws.length + 1;
        int maxJ = T + 1;

        int[][] dp = new int[maxI][maxJ];

        for (int i = 0; i < maxI; i++) {
            for (int j = 0; j < maxJ; j++) {
                if (i == 0 || j == 0) continue; // 第0行或第0列最大报酬保持0

                int t = tws[i - 1][0];// 要选择的工作的[权重]
                int w = tws[i - 1][1];// 要选择的工作的[价值]

                if (t > j) {
                    // 如果要选择的工作的权重 > 当前背包权重,则无法放入背包,最大价值继承自上一行该列值
                    dp[i][j] = dp[i - 1][j];
                } else {
                    // 如果要选择的工作的权重 <= 当前背包权重
                    // 则我们有两种选择
                    // 1、不进行该工作,则最大价值继承自上一行该列值
                    // 2、进行该工作,则纳入该工作的价值w,加上+ 剩余权重,在不进行该工作的范围内,可得的最大价值dp[i - 1][j - t]
                    // 比较两种选择下的最大价值,取最大的
                    dp[i][j] = Math.max(dp[i - 1][j], w + dp[i - 1][j - t]);
                }
            }
        }

        return dp[maxI - 1][maxJ - 1];
    }
}

优化后代码

import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    int T = sc.nextInt();
    int n = sc.nextInt();

    int[][] tws = new int[n + 1][2];
    for (int i = 1; i <= n; i++) {
      tws[i][0] = sc.nextInt();
      tws[i][1] = sc.nextInt();
    }

    System.out.println(getResult(n, T, tws));
  }

  /**
   * @param T 工作时长
   * @param tws 数组,元素是tw,也是数组,含义为[该工作消耗的时长, 该项工作的报酬]
   * @return 最大报酬
   */
  public static int getResult(int n, int T, int[][] tws) {
    int[][] dp = new int[n + 1][T + 1];

    for (int i = 1; i <= n; i++) {
      int t = tws[i][0]; // 要选择的工作的[时长]
      int w = tws[i][1]; // 要选择的工作的[价值]
      for (int j = 1; j <= T; j++) {
        // 注意这里j不能从t开始,会遗漏处理j < t的情况
        if (j < t) {
          dp[i][j] = dp[i - 1][j];
        } else {
          dp[i][j] = Math.max(dp[i - 1][j], w + dp[i - 1][j - t]);
        }
      }
    }

    return dp[n][T];
  }
}

Python算法源码

# 输入获取
t, n = map(int, input().split())
tws = [list(map(int, input().split())) for i in range(n)]


# 算法入口
def getResult(t, tws):
    """
    :param t: 工作时长
    :param tws: 列表,元素是tw,也是列表,含义为[该工作消耗的时长, 该项工作的报酬]
    :return: 最大报酬
    """
    maxI = len(tws) + 1
    maxJ = t + 1

    # 默认将dp二维列表元素全部初始化为0
    dp = [[0 for j in range(maxJ)] for i in range(maxI)]

    for i in range(maxI):
        for j in range(maxJ):
            if i == 0 or j == 0:
                continue  # 第0行或第0列最大报酬保持0

            t, w = tws[i - 1]  # 要选择的工作的[权重,价值]

            if t > j:
                # 如果要选择的工作的权重 > 当前背包权重,则无法放入背包,最大价值继承自上一行该列值
                dp[i][j] = dp[i - 1][j]
            else:
                # 如果要选择的工作的权重 <= 当前背包权重
                # 则我们有两种选择
                # 1、不进行该工作,则最大价值继承自上一行该列值
                # 2、进行该工作,则纳入该工作的价值w,加上 + 剩余权重,在不进行该工作的范围内,可得的最大价值dp[i - 1][j - t]
                # 比较两种选择下的最大价值,取最大的
                dp[i][j] = max(dp[i - 1][j], w + dp[i - 1][j - t])

    return dp[-1][-1]  # 取二维列表最右下角元素作为题解


# 算法调用
print(getResult(t, tws))

优化后代码

# 输入获取
T, n = map(int, input().split())
tws = [list(map(int, input().split())) for i in range(n)]


# 算法入口
def getResult(n, T, tws):
    """
    :param n: 工作数量
    :param T: 工作时长
    :param tws: 列表,元素是tw,也是列表,含义为[该工作消耗的时长, 该项工作的报酬]
    :return: 最大报酬
    """
    tws.insert(0, [0, 0])

    # 默认将dp二维列表元素全部初始化为0
    dp = [[0 for j in range(T + 1)] for i in range(n + 1)]

    for i in range(1, n + 1):
        t, w = tws[i]  # 要选择的工作的[时长,价值]
        for j in range(1, T + 1): # 注意这里j不能从t开始,会遗漏处理j < t的情况
            if j < t:
                dp[i][j] = dp[i - 1][j]
            else:
                dp[i][j] = max(dp[i - 1][j], w + dp[i - 1][j - t])

    return dp[n][T]


# 算法调用
print(getResult(n, T, tws))

01背包滚动数组解法

关于01背包的滚动数组优化,请看算法设计 – 01背包问题的状态转移方程优化,以及完全背包问题_01背包问题状态转移方程_伏城之外的博客-CSDN博客

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
let T, n;
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 1) {
    [T, n] = lines[0].split(" ").map(Number);
  }

  if (n && lines.length === n + 1) {
    lines.shift();
    const tws = lines.map((line) => line.split(" ").map(Number));
    console.log(getResult(T, tws, n));
    lines.length = 0;
  }
});

/**
 *
 * @param {*} T 工作时长
 * @param {*} tws 数组,元素是tw,也是数组,含义为[该工作消耗的时长, 该项工作的报酬]
 * @param {*} n 工作数量
 */
function getResult(T, tws, n) {
  tws = [[0, 0], ...tws];
  const dp = new Array(T + 1).fill(0);

  // 01背包问题滚动数组优化
  for (let i = 1; i <= n; i++) {
    const [t, w] = tws[i];
    // 注意背包承重遍历必须倒序,正序的话就变成完全背包了
    for (let j = T; j >= t; j--) {
      dp[j] = Math.max(dp[j], dp[j - t] + w);
    }
  }

  return dp[T];
}

Java算法源码

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
  static ArrayList<Integer[]> nodes;

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

    int T = sc.nextInt();
    int n = sc.nextInt();

    Integer[][] tws = new Integer[n + 1][2];
    tws[0] = new Integer[] {0, 0};
    for (int i = 1; i <= n; i++) {
      tws[i][0] = sc.nextInt();
      tws[i][1] = sc.nextInt();
    }

    System.out.println(getResult(T, tws, n));
  }

  /**
   * @param T 工作时长
   * @param tws 数组,元素是tw,也是数组,含义为[该工作消耗的时长, 该项工作的报酬]
   * @param n 工作数量
   * @return 最大报酬
   */
  public static int getResult(int T, Integer[][] tws, int n) {
    int[] dp = new int[T + 1];

    // 01背包问题滚动数组优化
    for (int i = 1; i <= n; i++) {
      int t = tws[i][0];
      int w = tws[i][1];
      // 注意背包承重遍历必须倒序,正序的话就变成完全背包了
      for (int j = T; j >= t; j--) {
        dp[j] = Math.max(dp[j], dp[j - t] + w);
      }
    }

    return dp[T];
  }
}

Python算法源码

# 输入获取
T, n = map(int, input().split())
tws = [list(map(int, input().split())) for i in range(n)]


# 算法入口
def getResult(T, tws, n):
    """
    :param T: 工作时长
    :param tws: 列表,元素是tw,也是列表,含义为[该工作消耗的时长, 该项工作的报酬]
    :return: 最大报酬
    """
    tws.insert(0, [0, 0])
    dp = [0]*(T+1)

    # 01背包问题滚动数组优化
    for i in range(1, n+1):
        t, w = tws[i]
        # 注意背包承重遍历必须倒序,正序的话就变成完全背包了
        for j in range(T, t-1, -1):
            dp[j] = max(dp[j], dp[j - t] + w)

    return dp[T]


# 算法调用
print(getResult(T, tws, n))

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?