小庄在一次机缘巧合的机会,眼睛获取了黄金瞳,黄金瞳的功能是可以看到m种物品10天以后的价格。但是这些物品属于限购物资,最多只能购买一定的数量。现在小庄有资金x可以投资这些物品,如何操作才能实现10天后资产价值最大。
第一行 当前资金 x
第二行物品种类m
第三行每种物品限购数量,m个数字
第四行物品当前价格,m个数字
第五行物品10天后价格,m个数字
10天后资产价值最大值
11 2 6 5 3 2 5 3
18
第一种物品买3个,第二种物品买1个,初期资产3*3+2*1=11,10天后资产价值最大5*3+3*1=18
import java.util.Scanner; import java.util.Arrays; class Item { public int limit; public int cur; public int future; public Item(int limit){ this.limit = limit; } } public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x = sc.nextInt(); int m = sc.nextInt(); Item[] items = new Item[m]; for(int i = 0; i < m; i++){ items[i] = new Item(sc.nextInt()); } for(int i = 0; i < m; i++){ items[i].cur = sc.nextInt(); } for(int i = 0; i < m; i++){ items[i].future = sc.nextInt(); } int[][] dp = new int[m][x + 1]; System.out.println(Math.max(x, dfs(items, 0, x, dp))); } private static int dfs(Item[] items, int index, int rest, int[][] dp) { if(index == items.length || rest < items[index].cur){ // 钱不够或物品到头了,后面都无法再产生收益 return 0; } if(dp[index][rest] > 0){ return dp[index][rest]; } // 不选当前物品 int p1 = dfs(items, index + 1, rest, dp); // 选当前物品 int p2 = 0; for(int nums = 0; nums <= items[index].limit && nums * items[index].cur <= rest; nums++){ p2 = Math.max(p2, nums * items[index].future + dfs(items, index + 1, rest - nums * items[index].cur, dp)); } dp[index][rest] = Math.max(p1, p2); return dp[index][rest]; } }根据记忆化搜索可以改出动态规划,其实就是个背包问题
import java.util.Scanner; import java.util.Arrays; class Item { public int limit; public int cur; public int future; public Item(int limit){ this.limit = limit; } } public class Main { static int maxProfit = 0; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x = sc.nextInt(); int m = sc.nextInt(); Item[] items = new Item[m]; for(int i = 0; i < m; i++){ items[i] = new Item(sc.nextInt()); } for(int i = 0; i < m; i++){ items[i].cur = sc.nextInt(); } for(int i = 0; i < m; i++){ items[i].future = sc.nextInt(); } int[] dp = new int[x + 1]; for(int index = 0; index < m; index++){ for(int rest = x; rest >= items[index].cur; rest--){ int p = 0; for(int nums = 0; nums <= items[index].limit && nums * items[index].cur <= rest; nums++){ p = Math.max(p, rest + nums * items[index].future + dp[rest - nums * items[index].cur]); } dp[rest] = Math.max(dp[rest], p); } } System.out.println(dp[x]); } }===========================分割线=============================
import java.util.Scanner; import java.util.Arrays; class Item { public int limit; public int cur; public int future; public Item(int limit){ this.limit = limit; } } public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x = sc.nextInt(); int m = sc.nextInt(); Item[] items = new Item[m]; for(int i = 0; i < m; i++){ items[i] = new Item(sc.nextInt()); } for(int i = 0; i < m; i++){ items[i].cur = sc.nextInt(); } for(int i = 0; i < m; i++){ items[i].future = sc.nextInt(); } int[][] dp = new int[m][x + 1]; System.out.println(Math.max(x, dfs(items, 0, x, dp))); } private static int dfs(Item[] items, int index, int rest, int[][] dp) { if(index == items.length || rest < items[index].cur){ // 钱不够或物品到头了,后面都无法再产生收益,直接返回剩下的钱 return rest; } if(dp[index][rest] > 0){ return dp[index][rest]; } // 不选当前物品 int p1 = dfs(items, index + 1, rest, dp); // 选当前物品 int p2 = 0; for(int nums = 0; nums <= items[index].limit && nums * items[index].cur <= rest; nums++){ p2 = Math.max(p2, nums * items[index].future + dfs(items, index + 1, rest - nums * items[index].cur, dp)); } dp[index][rest] = Math.max(p1, p2); return dp[index][rest]; } }动态规划也要做出相应的修改,这里就不写了
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x = sc.nextInt(); int m = sc.nextInt(); // products[i][0]:限购数量,products[i][1]:当前价格,products[i][2]:10天后价格 int[][] products = new int[m][3]; for (int j = 0; j < 3; j++) { for (int i = 0; i < m; i++) { products[i][j] = sc.nextInt(); } } System.out.println(maxProfit(x, products)); } private static int maxProfit(int x, int[][] products) { // 根据单位价格可获取的利润排序,如:现在3元,10天后5元,单位价格的利润为(5-3)/3 Arrays.sort(products, (a, b) -> (b[2] - b[1]) * a[1] - (a[2] - a[1]) *b[1]); // 下标索引代表未花的钱,mem[i]代表此时的能够拥有的最大资金 int[] mem = new int[x + 1]; mem[x] = x; // 一个商品都不买时,最大资金即为原有资金 // recursion with memorization backtrack(x, products, mem); int ans = x; for (int item : mem) { ans = Math.max(ans, item); } return ans; } private static void backtrack(int remX, int[][] products, int[] mem) { for (int[] product : products) { // 有利润 && 仍可购买 && mem[remX - product[1]]未更新过 // 排序过的数组保证第一次存储的mem[i]即为最优 if (product[1] < product[2] && product[0] > 0 && remX - product[1] >= 0 && mem[remX - product[1]] == 0) { product[0]--; mem[remX - product[1]] = mem[remX] + product[2] - product[1]; backtrack(remX - product[1], products, mem); product[0]++; } } } }
#include<iostream> #include<vector> using namespace std; int main() { int bagSize; cin>>bagSize; int num; cin>>num; vector<int> nums(num); for (int i = 0; i < num; ++i) { cin>>nums[i]; } vector<int> weights(num); for (int i = 0; i < num; ++i) { cin>>weights[i]; } vector<int> values(num); for (int i = 0; i < num; ++i) { cin>>values[i]; } for (int i = 0; i < num; ++i) { int count = nums[i]; while (count > 1) { weights.emplace_back(weights[i]); values.emplace_back(values[i]); --count; } } vector<int> dp(bagSize + 1, 0); for (int i = 0; i < weights.size(); ++i) { for (int j = bagSize; j >= weights[i]; --j) { dp[j] = max(dp[j], dp[j - weights[i]] + values[i]); } } // for (auto& w : weights) cout << w << ' '; // cout << endl; // for (auto& v : values) cout << v << ' '; // cout << endl; int i = bagSize; while (i > 0 && dp[i] == dp[i - 1]) { --i; } int res = dp[i] + bagSize - i; cout << res << endl; return 0; }转化为0-1背包问题,考虑到一个情况是,如果背包装不满,就是钱没用完的话,总收益等与10天后的收益+之前剩余的钱
import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int x = scanner.nextInt(); int m = scanner.nextInt(); int[] lim = new int[m]; int[] a = new int[m]; int[] b = new int[m]; for (int i = 0; i < m; i++) lim[i] = scanner.nextInt(); for (int i = 0; i < m; i++) a[i] = scanner.nextInt(); for (int i = 0; i < m; i++) b[i] = scanner.nextInt(); int[][] dp = new int[m + 1][x + 1]; for (int j = 0; j <= x; j++) dp[0][j] = j; for (int i = 1; i <= m; i++) for (int j = 1; j <= x; j++) for (int k = 0; k <= Math.min(lim[i - 1], j / a[i - 1]); k++) dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * a[i - 1]] + k * b[i - 1]); System.out.println(dp[m][x]); } }
my_money = int(input().strip()) class_num = int(input().strip()) num_class = list(map(int, input().strip().split())) price_now = list(map(int, input().strip().split())) price_after = list(map(int, input().strip().split())) price_make = [] for i in range(len(price_now)): price_make.append(price_after[i] - price_now[i]) now_price = [] make_price = [] for i in range(class_num): for j in range(num_class[i]): now_price.append(price_now[i]) make_price.append(price_make[i]) dp = [[0 for i in range(my_money+1)] for i in range(len(now_price))] for j in range(1, my_money+1): if j >= now_price[0]: dp[0][j] = make_price[0] for i in range(len(now_price)): for j in range(1, my_money+1): if now_price[i] > j: dp[i][j] = dp[i-1][j] else: dp[i][j] = max(dp[i-1][j], dp[i-1][j - now_price[i]] + make_price[i]) print(my_money+dp[-1][-1])
多重背包问题,展开为0-1背包问题
package main import ( "bufio" "fmt" "os" "strconv" "strings" ) func main() { atoi := func(x []string) []int { t := []int{} for _, val := range x { if val==""{ continue } tmp, _ := strconv.Atoi(val) t = append(t, tmp) } return t } scanner := bufio.NewScanner(os.Stdin) scanner.Scan() x, _ := strconv.Atoi(scanner.Text()) scanner.Scan() m, _ := strconv.Atoi(scanner.Text()) scanner.Scan() xg := atoi(strings.Split(scanner.Text(), " ")) scanner.Scan() curPrice := atoi(strings.Split(scanner.Text(), " ")) scanner.Scan() futurePrice := atoi(strings.Split(scanner.Text(), " ")) ans := MySolution(x, m, xg, curPrice, futurePrice) fmt.Println(ans) } func MySolution(x, m int, xg []int, curPrice []int, futurePrice []int) int { // 本题是多重背包问题 // 将多重背包问题展开为0-1背包问题 for i := 0; i < m; i++ { count := xg[i] for count > 1 { curPrice = append(curPrice, curPrice[i]) futurePrice = append(futurePrice, futurePrice[i]) count-- } } max := func(a, b int) int { if a > b { return a } return b } dp := make([]int, x+1) //0-x的下标,表示背包的容量从0-x for i := 0; i < len(curPrice); i++ { // 逆序为0-1,正序为完全背包 for j := x; j >= curPrice[i]; j-- { dp[j] = max(dp[j], dp[j-curPrice[i]]+futurePrice[i]) } } i:=x for i>0&&dp[i]==dp[i-1]{ i-- //获取用掉的钱 } return (dp[i]+x-i) }