首页 > 试题广场 >

外卖满减

[编程题]外卖满减
  • 热度指数:5693 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
你打开了美了么外卖,选择了一家店,你手里有一张满 X 元减 10 元的券,店里总共有 n 种菜,第 i 种菜一份需要 Ai 元,因为你不想吃太多份同一种菜,所以每种菜你最多只能点一份,现在问你最少需要选择多少元的商品才能使用这张券。

数据范围: ,

输入描述:
第一行两个正整数n和X,分别表示菜品数量和券的最低使用价格。 接下来一行n个整数,第i个整数表示第i种菜品的价格。


输出描述:
一个数,表示最少需要选择多少元的菜才能使用这张满X元减10元的券,保证有解。
示例1

输入

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;
}


编辑于 2020-03-24 19:36:05 回复(6)
//抄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;
}


发表于 2019-09-11 14:24:50 回复(3)
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]);
    }
}
发表于 2019-08-07 23:07:24 回复(1)
背包问题,使用动态规划求解
1.最常规的背包问题求解(使用二维数组)
dp[i][j]表示从菜品0~i中进行选择,订单不超过j元能达到的最高消费
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);
    }
}
2.对背包问题进行时间复杂度和空间复杂度的优化
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])


编辑于 2021-02-02 16:10:21 回复(0)
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]);
	}

发表于 2019-08-18 21:52:07 回复(0)
"""
一个集合解决问题
"""
if __name__ == '__main__':
    n, x = list(map(int, input().strip().split()))
    a = list(map(int, input().strip().split()))
    ans = {0, }
    for c in a:
        for d in list(ans):
            ans.add(c + d)
    ans = [c for c in ans if c >= x]
    print(min(ans))

发表于 2019-10-05 12:33:59 回复(1)
#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;
}

编辑于 2019-10-17 21:18:13 回复(0)
//动态规划——反向的01背包问题
//要求在超过X元的情况下选择价格总和最少的菜品,可以理解为在不超过(菜品总价T)-X的情况下,选择菜品价格总和最多的菜品——B(n,T-X)问题。
//剩下的就是超过X元的情况下选择价格总和最少的菜品。
 
#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;
}


编辑于 2020-07-05 11:32:32 回复(0)

题意,每件商品只能买一次,至少需要买多少钱的东西才能满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);
    }
}
发表于 2020-06-24 10:42:26 回复(0)
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);
    }
}

发表于 2019-08-28 19:50:33 回复(0)
#include <stdio.h>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

int main()
{
 int n;
 cin >> n;
 int X;
 cin >> X;
 int sum = 0;
 vector<int> s;
 vector<int> se1;
 set<int> test;
 int resmin = 1000000;
 for (int i = 0; i < n; ++i)
 {
  int temp;
  cin >> temp;
  s.push_back(temp);
 }

 sort(s.begin(),s.end());

 for (int j = 0; j < n; ++j)
 {
  sum += s[j];
  se1.push_back(s[j]);
  if (sum == X)
  {
   cout << sum;
   return 0;
  }

  if (sum > X)
  {
   int flag = 0;
   int temp = sum-X;
   int min = 100000;
   for (int i = 0; i < se1.size(); ++i)
   {
    int temp1 = temp - se1[i];

    if (temp1>=0 && temp1 < min)
    {
     min = temp1;
     flag = i;
    }
   }//获取最接近当前差的元素

   sum = sum - se1[flag];
   if (sum == X)
   {
    cout << sum;
    return 0;
   }

   if (sum > X)
   {
    if (sum < resmin)
     resmin = sum;

    se1[flag] = 0;
   }

   else
   {
    sum = sum + se1[flag];
    se1.pop_back();
   }
  }
 }

 cout << sum;
 return 0;
}
发表于 2019-08-18 21:09:03 回复(3)
#include <iostream>
using namespace std;

int main()
{
    int n, th;
    cin >> n >> th;
    int* v = new int[n];
    for(int i=0; i<n; i++) 
        cin >> v[i];
    
    int sum = 0;
    for(int i=0; i<n; i++)
        sum += v[i];
    
    int m = sum-th;
    int* dp = new int[m+1];
    for(int i=0; i<n; i++)
    {
        for(int j=m; j>=v[i]; j--)
        {
            dp[j] = max(dp[j], dp[j-v[i]]+v[i]);
        }
    }
    
    cout << sum-dp[m] << endl;
    
    delete dp;
    delete v;
}
发表于 2022-08-24 20:09:55 回复(0)
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]);
    }
}

发表于 2021-10-26 20:50:13 回复(0)
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);
    }

}



发表于 2021-07-29 21:27:20 回复(0)
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]);
    }
}
背包问题(参考大佬的)
发表于 2021-05-15 00:47:35 回复(0)
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])
背包问题的一个小变种

发表于 2021-03-13 13:07:25 回复(0)
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
    int n,x;
    cin>>n>>x;
    vector<int> v(n);
    int temp=65535;
    for(int i=0;i<n;i++) cin>>v[i];
     vector<vector<int> > dp(n+1,vector<int>(x+1,0));
    for(int i=1;i<=x;i++) dp[0][i]=65535;
     for(int i=1;i<=n;i++){
         for(int j=1;j<=x;j++){
             if(j>=v[i-1]) dp[i][j]=min(dp[i-1][j],dp[i-1][j-v[i-1]]+v[i-1]);
             else dp[i][j]=min(dp[i-1][j],v[i-1]);
         }
     }
    cout<<dp[n][x];
    return 0;
}
发表于 2020-09-01 11:20:29 回复(0)
我擦啊,这题好难啊,关键是看了半天,没一个讲的明白的,或者没一个看的明白的。
发表于 2020-08-21 17:03:15 回复(0)
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);
        }
    }
}

发表于 2020-08-14 17:16:42 回复(0)
//一张满X元减10元优惠券
//菜单,第i种菜A_i元
//需要选择最少多少元才能使用这个优惠券

import java.lang.*;
import java.util.*;


//d[i][j]表示到第i道菜为止,能满足优惠卷j的最小总菜价
//其递推关系为:d[i][j] = Math.min(d[i-1][j],input[i-1]+d[i-1][j-input[i-1]]);
//d[i-1][j]表示到第i-1道菜为止,能满足优惠卷j的最小总菜价,即没有点第i道菜
//d[i-1][j-input[i-1]]表示到第i-1道菜为止,能满足优惠卷j-input[i-1]的最小总菜价
//这样input[i-1]+d[i-1][j-input[i-1]]就可以代表点了第i道菜的时候且优惠卷是j的最小菜价了

//边缘问题1,j==0&&i!=0,当j<input[i-1]时,表示一盘菜就满足了,将d[i-1][j-input[i-1]]替换为0
//边缘问题2,i==0&&j!=0,初始化问题,因为是比较最小值,初始化的值应当为最大值。即,当i==0时,初始化值为
//Integer.MAX_VALUE。
//边缘问题3,当i==0&&j==0时,将其同边缘问题2一同处理



public class Main{
    
    private int solution(int[] input,int target){
        int[][] d = new int[input.length+1][target+1];
        
        //初始化,当i==0时
        for(int j = 0;j<target+1;j++){
            d[0][j] = 10001;
        }
        
        //初始化,当j==0时
        for(int i = 1;i < input.length+1;i++){
            d[i][0] = input[i-1];
        }
        
        for(int i = 1;i < input.length+1;i++){
            for(int j = 1;j < target+1;j++){
                if(j-input[i-1]<=0){
                    d[i][j] = Math.min(d[i-1][j],input[i-1]);
                }else{
                    d[i][j] = Math.min(d[i-1][j],
                    input[i-1]+d[i-1][j-input[i-1]]);
                }
            }
        }
        return d[input.length][target];
    }
    
    
    
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int n = sc.nextInt();
        int X = sc.nextInt();
        
        int[] input = new int[n];
        
        int index = 0;
        
        while(index<n){
            input[index++] = sc.nextInt();
        }
        
        Main main = new Main();
        
        System.out.println(main.solution(input,X));
    }
}
发表于 2020-07-31 16:06:17 回复(0)