你打开了美了么外卖,选择了一家店,你手里有一张满 X 元减 10 元的券,店里总共有 n 种菜,第 i 种菜一份需要 Ai 元,因为你不想吃太多份同一种菜,所以每种菜你最多只能点一份,现在问你最少需要选择多少元的商品才能使用这张券。
数据范围: ,
第一行两个正整数n和X,分别表示菜品数量和券的最低使用价格。 接下来一行n个整数,第i个整数表示第i种菜品的价格。
一个数,表示最少需要选择多少元的菜才能使用这张满X元减10元的券,保证有解。
5 20 18 19 17 6 7
23
额,我的思路可能有点清奇且复杂😥,不过应该挺容易理解。我把它理解为“反向的”01背包问题,即:
若所有菜品总价为T,优惠券为满X减?元,则可以转化为容量为T-X的01背包问题,本题的特殊之处在于每一件物品的体积等于其价值也就是每样菜品的价格
也就是说,在超过X元的情况下选择价格总和最低的菜品等价于,在不超过T-X的情况下尽可能选择价值总和最高的物品
#include <iostream> using namespace std; int main(){ int n,X; while(cin>>n>>X){ int price[100]={0}; int total=0; for(int i=0;i<n;i++){ cin>>price[i]; total+=price[i]; } int V=total-X; int *dp=new int[V+1]; for(int i=0;i<=V;i++) dp[i]=0; for(int i=1;i<=n;i++) for(int j=V;j>=price[i-1];j--){ dp[j]=max(dp[j-price[i-1]]+price[i-1],dp[j]); } cout<<total-dp[V]<<endl; delete[] dp; } return 0; }
//抄hippostar同学的: #include<bits/stdc++.h> using namespace std; int main() { int n,X; cin >> n >> X; vector<int> dp(X+1,10001);//dp[I]是消费达到I 元所需的最低消费 int price; for(int i =0;i<n;i++){ cin >> price; for(int j = X;j>=0;j--){ if(j>price){ dp[j]=min(dp[j],dp[j-price]+price); } else{ dp[j]=min(dp[j],price); } } } cout << dp[X]<< endl; return 0; }
import java.util.*; public class Main { private static int len = 0; public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int x = in.nextInt(); int[] xs = new int[x+1]; for(int i=0;i<=x;i++){ xs[i]=10001; } for(int i=0;i<n;i++){ int price = in.nextInt(); for(int j=x;j>=0;j--){ if(j>price){ //如果凑单价格大于当前price,那么就看下原来的凑单价最小还是 //当前菜品的价格,加上j-price的价格最少需要多少元凑单 xs[j] = Math.min(xs[j],xs[j-price]+price); }else{ //如果当前凑单价格小于等于price,必须点当前price的菜,除非有比当前价格更小的菜 xs[j] = Math.min(xs[j],price); } } } System.out.println(xs[x]); } }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] strNX = br.readLine().trim().split(" "); int n = Integer.parseInt(strNX[0]), x = Integer.parseInt(strNX[1]); String[] strPrice = br.readLine().trim().split(" "); int sum = 0; int[] price = new int[n]; for(int i = 0; i < n; i++){ price[i] = Integer.parseInt(strPrice[i]); sum += price[i]; } // dp[i][j]表示对于菜品0~i,不超过j元的情况下最多能下单多少元 int[][] dp = new int[n + 1][sum + 1]; // 动态规划求解背包问题 for(int i = 1; i <= n; i++){ for(int j = 1; j <= sum; j++){ dp[i][j] = dp[i - 1][j]; // 不选第i件菜品 if(j >= price[i - 1]) // 选第i件菜品 dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - price[i - 1]] + price[i - 1]); } } // 遍历所有状态,找到大于等于x的最低消费即可 int lower_bound = sum; for(int i = 1; i <= n; i++) { for(int j = 1; j <= sum; j++) { if(dp[i][j] >= x) // 达到满减条件,更新最小值 lower_bound = Math.min(dp[i][j], lower_bound); } } System.out.println(lower_bound); } }
n, X = map(int, input().strip().split()) price = list(map(int, input().strip().split())) dp = [10001]*(X + 1) # dp[i]表示达到i元的最低消费 for i in range(n): for j in range(X, -1, -1): dp[j] = min(dp[j], (dp[j - price[i]] if j > price[i] else 0) + price[i]) print(dp[X])
public static void main(String[] args) { // TODO Auto-generated method stub Scanner sc = new Scanner(System.in); int n = sc.nextInt();// 菜品数量 int x = sc.nextInt(); // 优惠券价格 int arr[] = new int[n]; for(int i=0 ;i < n; i++){arr[i] = sc.nextInt();}// 菜品单价 int[][] v = new int[n+1][x+1]; System.out.println(v.length +","+v[0].length); // 当菜品数量=0,优惠券价格=10001 ???只要大于10000即可 for(int i= 0; i<=x ;i++){v[0][i] = 10001;} // 优惠券价格为0的情况,可不设置,默认为0 //for(int i= 0; i<n ;i++){v[i][0] = 0;} // 循环求解,求放入背包的最小值 for(int i=1; i<= n; i++){ // 从第一个物品开始 for(int j=1 ;j <=x; j++){ // 从背包容量=1 开始 if(arr[i-1] >= j){ // 当前物品价格 > 背包容量 v[i][j] = Math.min(arr[i-1], v[i-1][j]); // 选之前和当前价格最小的 //v[i][j] = v[i-1][j]; // 选之前和当前价格最小的 }else{ // 当前物品价格 < 背包容量 // 选 min(之前的策略,把当前物品装入后剩余背包能装最少的物品) 两者最小值 v[i][j] = Math.min(v[i-1][j], arr[i-1] + v[i-1][j-arr[i-1]]); } } } //for(int[] arr1: v){System.out.println(Arrays.toString(arr1));} System.out.println(v[n][x]); }
#include <bits/stdc++.h> using namespace std; int main(){ int n,x; cin>>n>>x; vector<int> arr(n,0); vector<vector<int>> dp(n,vector<int>(x+1,9999)); for(int i=0;i<n;i++) cin>>arr[i]; for(int j=0;j<=x;j++) if(arr[0]>=j) dp[0][j]=arr[0]; for(int i=1;i<n;i++) dp[i][0]=min(dp[i-1][0],arr[i]); for(int i=1;i<n;i++){ for(int j=1;j<=x;j++){ dp[i][j]=dp[i-1][j]; if(dp[i][j-1]>=j) dp[i][j]=min(dp[i][j],dp[i][j-1]); if(j==arr[i]) dp[i][j]=arr[i]; else if(j>arr[i]) dp[i][j]=min(dp[i-1][j-arr[i]]+arr[i],dp[i][j]); } } cout<<dp[n-1][x]; return 0; }
#include<iostream> #include<vector> usingnamespacestd; intmax(inta, intb) { if(a >= b) { returna; } else { returnb; } } intmain() { intn, X; cin >> n >> X; int*p = newint[n+1]; for(inti = 1; i <= n; i++) { cin >> p[i]; } inttotal = 0; for(inti = 1; i <= n; i++) { total += p[i]; } vector<int>dp(total - X + 1, 0); for(inti = 1; i <= n; i++) { for(intj = total - X; j >= 1; j--) { if(j >= p[i]) { dp[j] = max(dp[j], dp[j - p[i]] + p[i]); } } } cout << total - dp[total - X] << endl; return0; }
题意,每件商品只能买一次,至少需要买多少钱的东西才能满X元钱。
如果我们知道了背包的容量大小,也就是我们有一共多少钱,目标就变成了,我们尽可能的买最多的东西,也就是使得总的价值最大。
我们依次枚举我们钱的大小(背包大小),求出背包大小固定的情况下,最大价值。
f[i][j]
表示前i个商品的情况下,背包大小为j时,能买商品的价格最大值。
典型01背包问题状态转移:
f[i][j]=f[i-1][j]
, 不选的第i件商品
f[i][j] = f[i-1][j-a[i]], j >= a[i]
, 背包容量够的情况下选择第i件商品。
我们遍历所有状态,求出价格最大值大于X 中最小的价值,就是该问题的答案。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(), x = sc.nextInt(); int[] a = new int[n]; int sum = 0; for(int i=0; i < n; i++) { a[i] = sc.nextInt(); sum += a[i]; } int[][] f = new int[n+1][sum+1]; for(int i=1; i <= n; i++) { for(int j=1; j <= sum; j++) { if(i == 1) { if(j >= a[i-1]) f[i][j] = a[i-1]; continue; } f[i][j] = f[i-1][j]; if(j - a[i-1] >= 0) f[i][j] = Math.max(f[i][j], f[i-1][j - a[i-1]] + a[i-1]); } } //System.out.println(Arrays.deepToString(f)); int res = sum; for(int i=1; i <= n; i++) { for(int j=1; j <= sum; j++) { if(f[i][j] >= x && f[i][j] < res) res = f[i][j]; } } System.out.println(res); } }
import java.io.*; public class Main{ public static void main(String[] args) throws IOException{ BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String[] line1=br.readLine().split(" "); int n=Integer.parseInt(line1[0]); int X=Integer.parseInt(line1[1]); String[] line2=br.readLine().split(" "); int[] costs=new int[n+1]; int sum=0; for(int i=1;i<=n;i++){ costs[i]=Integer.parseInt(line2[i-1]); sum+=costs[i]; } int[][] dp=new int[n+1][sum+1]; for(int i=1;i<=n;i++){ for(int j=0;j<=sum;j++){ dp[i][j]=dp[i-1][j]; if(j>=costs[i]){ dp[i][j]=Math.max(dp[i][j],dp[i-1][j-costs[i]]+costs[i]); } } } int res=X; while(true){ if(dp[n][res]>=X){ break; } res++; } System.out.println(res); } }
import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int x = scanner.nextInt(); int[] A = new int[n]; int sum = 0; for (int i = 0; i < n; i++) { A[i] = scanner.nextInt(); sum += A[i]; } int[][] dp = new int[n + 1][sum - x + 1]; for (int i = 1; i <= n; i++) { for (int j = 0; j <= sum - x; j++) { if (j >= A[i - 1]) { dp[i][j] = Math.max( dp[i - 1][j], dp[i - 1][j - A[i - 1]] + A[ i - 1] ); } else { dp[i][j] = dp[i - 1][j]; } } } System.out.print(sum - dp[n][sum - x]); } }
import javax.net.ssl.SSLContext; import java.lang.management.BufferPoolMXBean; import java.math.BigInteger; import java.util.*; import java.io.*; import java.util.concurrent.Phaser; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.ReentrantLock; /** 01背包问题的衍生简单扩展版本--- 求得是满足达到固定价值的最小体积 直接用01背包的滚动优化版本就好了 时间复杂度 100 * 10000 = 1e6 没啥压力 */ public class Main { static int N = 110, M = 10010, n, m; static int[] f = new int[M]; static int[] nums = new int[N]; static int res; public static void main(String[] args) { Scanner in = new Scanner(System.in); n = in.nextInt(); m = in.nextInt(); for(int i = 0; i < n; i ++){ int x = in.nextInt(); for(int j = M - 1; j >= x; j --) f[j] = Math.max(f[j], f[j - x] + x); // 01背包模板 } for(int i = m; i < M; i ++){ //求可以大于m的最小体积 if(f[i] >= m){ res = i; break; } } System.out.println(res); } }
import java.io.*; import java.util.Scanner; public class Main { public static void main(String[] args) throws IOException { Scanner in = new Scanner(System.in); int n = in.nextInt(); int k = in.nextInt(); int[] ele = new int[n+1]; int res = 0; for (int i = 1; i <= n; i++) { ele[i] = in.nextInt(); res += ele[i]; } //背包 总容量为菜品总价-满减价格 //价值为菜品,体积也为菜品 //在容量不大于总容量时,选择最大价值的 int v = res - k; int[] dp = new int[v + 1]; //物品个数 for (int i = 1; i <= n; i++) { //背包容量 for (int j = v; j >= ele[i]; j--) { dp[j] = Math.max(dp[j], dp[j - ele[i]] + ele[i]); } } System.out.println(res - dp[v]); } }背包问题(参考大佬的)
n, x = list(map(int, input().strip().split())) val = list(map(int, input().strip().split())) dp = [sum(val)]*(x+1) for i in range(1, n+1): for j in range(x, 0, -1): if val[i-1] < j: dp[j] = min(dp[j], val[i-1]+dp[j-val[i-1]]) else: dp[j] = min(dp[j], val[i-1]) print(dp[x]) 背包问题的一个小变种
import java.util.*; import java.io.*; public class Main{ public static void main(String[] args)throws Exception{ BufferedReader dr=new BufferedReader(new InputStreamReader(System.in)); String de; while((de=dr.readLine())!=null){ String[] df=de.split(" "); int n=Integer.valueOf(df[0]); int v=Integer.valueOf(df[1]); String[] res1=dr.readLine().split(" "); int[] res=new int[n]; int sum=0; int min=Integer.MAX_VALUE; for(int i=0;i<n;i++){ res[i]=Integer.valueOf(res1[i]); sum+=res[i]; } Arrays.sort(res); int max=0; int flag=0; boolean[] dp=new boolean[sum+1]; dp[0]=true; for(int d:res){ for(int i=sum;i>=0;i--){ if(i>=d){ dp[i]=dp[i-d]|dp[i]; }else{ break; } if(i>=v&&dp[i]){ min=Math.min(i,min); } } } System.out.println(min); } } }