首页 > 试题广场 >

代金券组合

[编程题]代金券组合
  • 热度指数:3120 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

近期某商场由于周年庆,开启了“0元购活动。活动中,消费者可以通过组合手中的代金券,实现0元购买指定商品。

聪明的小团想要用算法来帮助他快速计算:对于指定价格的商品,使用代金券凑出其价格即可,但所使用的代金券总面额不可超过商品价格。由于代金券数量有限,使用较少的代金券张数则可以实现价值最大化,即最佳优惠。

假设现有100元的商品,而代金券有50元、30元、20元、5元四种,则最佳优惠是两张50元面额的代金券;而如果现有65元的商品,则最佳优惠是两张30元代金券以及一张5元代金券。

请你帮助小团使用一段代码来实现代金券计算。


输入描述:
多组输入输出,读到s=0时结束
输入可以有多个测试样例,每个测试由两行组成。

其中第一行包含一个整数P,表示商品的价格,1≤P≤10000;输入P为0时表示结束。

第二行包含若干整数,使用空格分割。其中第一个整数N(1≤N≤20)表示有多少种代金券,其后跟随M个整数,表示手中持有的代金券面额(1≤N≤1000),每种代金券数量不限。



输出描述:

找到最少张数的代金券,使其面额恰好等于商品价格。输出所使用的代金券数量;

如果有多个最优解,只输出其中一种即可;

如果无解,则需输出“Impossible”。

示例1

输入

65
4 50 30 20 5
0

输出

3
var price=parseInt(readline());
var scdLine=readline().split(' ');
var types=scdLine[0];
var coupons=scdLne.slice(1).map(Number);

function couponNum(price){
    var flag=false;
    coupons.sort();
    var result=0;
    
    function calc(curPrice){
        if(!curPrice||coupons[0]>curPrice){
        console.log('Impossible');
        return;
    }
    for(var i=types-1; i>=0; i--){
        var cur=coupons[i];
        if(flag){return};
        if(cur>curPrice){
            continue;
        }
        result+=Math.floor(curPrice/cur);
        if(curPrice%cur){
            calc(curPrice%cur);
        }else{flag=true}
      }
    }
    
    console.log(result);
    return result;
}
哪里有问题
编辑于 2020-08-15 00:51:31 回复(0)
while(true){
    let nums = parseInt(readline())
    if(nums === 0 ) break
    let coins = readline().split(" ").map(Number).slice(1)
    console.log(fn(coins,nums))
}
function fn(coins,nums){
    let dp = new Array(nums+1).fill(Infinity)
    dp[0] = 0
    for(let i = 1;i<=nums;i++){
        for(let coin of coins){
            if( i >= coin ){
                dp[i] = Math.min(dp[i],dp[i-coin]+1)
            }
        }
    }
    return dp[nums] === Infinity ? 'Impossible' : dp[nums]
}

发表于 2020-03-13 10:56:05 回复(6)

JavaScript 2020美团-代金券组合😎dp
leet322 今天0308的每日一题

const readline = require('readline')
const rl = readline.createInterface({
    input: process.stdin,
    ouput: process.stdout
})
let inArr = []
rl.on('line', line=>{
    if(!line) return
    inArr.push(line.trim())
    if(inArr[inArr.length-1]==0){
        for (let i = 0; i < inArr.length-2; i+=2) {
            let amount = +inArr[i]
            let coins = inArr[i+1].split(' ').map(e=>+e)
            console.log(coinChange(coins, amount))
            
        }
    }
})

var coinChange = function(coins, amount) {
    let dp = new Array(amount+1).fill(Infinity)
    dp[0] = 0
    for (let coin of coins ) {
      for (let i = 1; i <= amount; i++) {
        if (i - coin >= 0) {
          dp[i] = Math.min(dp[i], dp[i - coin] + 1)
        }
      }
    }
    return dp[amount] === Infinity ? 'Impossible' : dp[amount]
  }
发表于 2020-03-08 18:39:02 回复(1)
js输入都要搞好久
while(true){   
    var num = parseInt(readline())
    if(num==0){
        break
    }
    var lines =readline()
    var lineArr = lines.split(" ").map(Number)
    var type = lineArr[0]
    var money = lineArr.slice(1)
    console.log(getResult(num,type,money))
}

function getResult(num, type, money) {
        var dp = []
        dp[0]=0
        for (var i = 1; i <=num; i++) {
            var arr=[]
            for(var j=0;j<money.length;j++){
                if(i>=money[j]){
                    arr.push(dp[i-money[j]]+1)
                }
            }
            dp[i]=Math.min(...arr)
        }
    return dp[num]==Infinity?"Impossible":dp[num]
}


发表于 2020-03-10 20:30:04 回复(0)
// 只通过50%..
function mysort(a,b){
    if(a<b){
        return 1;
    }else if(a>b){
        return -1
    }else{
        return 0;
    }
}
while(true){
    var salary=parseInt(readline())
    if(salary==0){
        break;
    }
    var arr=readline().split(' ').map(Number)
    var n=arr[0]
    // 最小次数
    var min=10000;
    // 是否能满足条件的标识
    var flag=false;
    // 有个问题,输入的数组需要先排序。。并且从大到小
    arr=arr.slice(1).sort(mysort)
    for(var i=0;i<arr.length;i++){
        var inmin=0;
        if(salary>=arr[i]){
            if(salary==arr[i]){
                inmin=1;
                break;
            }
            var tem=Math.floor(salary/arr[i]);
            // 剩下的额度
            var a=salary-arr[i]*tem;
            inmin=tem;
            for(var j=i+1;j<arr.length;j++){
                if(a>=arr[j]){
                    var b=Math.floor(a/arr[j]);
                    inmin+=b;
                    a=a-b*arr[j]
                    if(a==0){
                        flag=true;
                        min=inmin<min?inmin:min;
                        break;
                    }
                }
            }
        }
    }
    print(flag?min:'Impossible')
}

发表于 2020-03-06 23:18:25 回复(0)
function fn(num, coinStr){
   let coinArr = coinStr.split(' ').map(Number).slice(1);
   let fnArr = [];
   fnArr[0] = 0;
   for(let i = 1; i<= num; i++){
       for(let c = 0; c<coinArr.length; c++){
            if(coinArr[c] <= i){
               fnArr[i] = Math.min(fnArr[i] || Infinity, fnArr[i-coinArr[c]]+1) || Infinity
            }
       }
   }
   return fnArr[num] === Infinity ? 'Impossible' : fnArr[num];
}

console.log(fn(10,'4 50 30 20 5'))
编辑于 2021-02-17 23:40:17 回复(0)
使用递归+贪心,若是直接使用递归则只能通过0.6,所以必须使用贪心思想进行解题
res = float('inf')
def DFS(num,i,r,target):
    global res
    if target == 0:
        res = min(res,r)
        return
    if target < 0:
        return
    if i >= len(num):
        return
    cur = target // num[i]
    j = cur
    while j >= 0:
        if r + j >= res:
            return
        else:
            DFS(num,i+1,r+j, target-num[i] * j)
            j -= 1
            
while True:
    target = int(input().strip())
    if target == 0:
        break
    num = list(map(int,input().strip().split()))
    num = sorted(num,reverse=True)
    res = float('inf')
    DFS(num,0,0,target)
    if res == float('inf'):
        print('Impossible')
    else:
        print(res)

发表于 2020-08-22 11:44:46 回复(0)
import sys
class Solution:
    def func(self, price, num, arr):
        arr.sort()
        if arr[0] > price:
            return "Impossible"
        dp = [0 for _ in range(price+1)]
        dp[0] = 0
        for i in range(1, arr[0]):
            dp[i] = "Impossible"
        dp[arr[0]] = 1
        for i in range(arr[0]+1, price+1):
            dp[i] = float('inf')
            for opt in arr:
                if i-opt < 0:
                    break
                if i-opt == 0:
                    dp[i] = 1
                if dp[i-opt] == "Impossible":
                    continue
                dp[i] = min(dp[i], dp[i-opt] + dp[opt])
            if dp[i] == float('inf'):
                dp[i] = "Impossible"
        return dp[price]
                     
if __name__ == '__main__':
    solution = Solution()
    while True:
        price = int(sys.stdin.readline().strip())
        if price == 0:
            break
        arr = list(map(int, sys.stdin.readline().strip().split()))
        num = arr.pop(0)
        print(solution.func(price, num, arr))



发表于 2020-04-08 09:06:32 回复(0)
//java代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {//可以用来判断是否有下一个整数
            int n = in.nextInt();
                        if(n == 0) break;
            if (in.hasNextInt()) {//如果还有下一个数,可以将其放入变量x中
                int x = in.nextInt();
                int arr[] = new int[x + 1];
                for (int i = 0; i < x; i++) {
                    arr[i] = in.nextInt();
                }
                int dp[] = new int[n + 1];
                Arrays.fill(dp, n + 1);
                dp[0] = 0;
                for (int i = 1; i <= n; i++) {
                    for (int j = 0; j < x; j++) {
                        if (arr[j] <= i) dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
                    }
                }
                System.out.println(dp[n] > n ? "Impossible" : dp[n]);
            }

        }
    }
}


发表于 2023-04-05 17:57:30 回复(0)
贴一贴 Java 的

leetcode  322 题
import java.util.*;

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

        while (sc.hasNextLine()){
            s=sc.nextLine();
            if(s=="0") break;
            k++;
            if(k%2==1){
                v=Integer.valueOf(s.trim());
            }
            if(k%2==0){
                String[] str=s.split(" ");
                int n= Integer.valueOf(str[0]);
                Map<Integer,Integer> map=new HashMap<>();
                ArrayList<Integer> list=new ArrayList<>();
                int[] val=new int[n];
                for(int i=1;i<=n;i++){
                    map.put(Integer.valueOf(str[i]),0);
                    list.add(Integer.valueOf(str[i]));
                    val[i-1]=Integer.valueOf(str[i]);
                }

                Arrays.sort(val);

                int dp[] =new int[v+1];
                Arrays.fill(dp,v+1);
                dp[0]=0;
                for(int i=1;i<=v;i++){
                    for(int j=0;j<n;j++){
                        if(val[j]<=i){
                            dp[i]=Math.min(dp[i],dp[i-val[j]]+1);
                        }
                    }
                }
                if(dp[v]>v){
                    System.out.println("Impossible");
                }else {
                    System.out.println(dp[v]);
                }
            }
        }
    }
}


发表于 2022-09-06 23:28:18 回复(0)
const readline = require('readline')
const rl = readline.createInterface({
    input: process.stdin,
    ouput: process.stdout
})
let inArr = []
rl.on('line', line => {
    if (!line) return
    inArr.push(line.trim())
    if (parseInt(inArr[inArr.length - 1]) == 0) {
        //collect amount and coin
        let amount = parseInt(inArr[0]);
        let coins = inArr[1].split(' ').map(Number);
        console.log(coinChange(amount, coins));

    }
})
function coinChange(amount, coins) {
    const dp = new Array(amount + 1).fill(Infinity)
    dp[0] = 0
    for (let i = 1; i <= amount; i++) {
        for (let j = 0; j < coins.length; j++) {
            if (i >= coins[j]) {
                dp[i] = Math.min(dp[i - coins[j]] + 1, dp[i])
            }
        }
    }
    return dp[amount] == Infinity ? "Impossible" : dp[amount]
}

发表于 2020-09-20 09:30:15 回复(0)
import java.util.*;
public class Main{
    static int count=0;
    static int s1,s2,s3,s4;
    public void f(int sun){
        int a=sun%5;
        int n=sun/5;
        int b,c,d,e;
        Main m=new Main();
        if(a != 0)
        {
            System.out.println("Impossible");
        }
        else {
            if(n>=10){
                b=n/10;
                s1=b;
                m.f(5*n-50*b);
            }else if(n>=6){
                c=n/6;
                s2=c;
                m.f(5*n-30*c);
            }else if(n>=4){
                d=n/4;
                s3=d;
                m.f(5*n-20*d);
            }else if(n>=1){
                e=n/1;
                s4=e;
            }
        }
    }
    public static void main(String[] args){
        Scanner sss=new Scanner(System.in);
        int sum=sss.nextInt();
        Main mmm=new Main();
        mmm.f(sum);
        count=count+s1+s2+s3+s4;
        System.out.println(count);
        for(int i = 0;i < s1;i++)
        {
            System.out.println(50);
        }
        for(int i = 0;i < s2;i++)
        {
            System.out.println(30);
        }
        for(int i = 0;i < s3;i++)
        {
            System.out.println(20);
        }
        for(int i = 0;i < s4;i++)
        {
            System.out.println(5);
        }
    }
}
思路正确,总是有一些小问题,在集成环境中可以很快完成,我直接换行了,思路正确
发表于 2020-04-11 17:48:11 回复(0)
function coupon(a,b)
{
  var f=new Array(a+1);
  f[0]=0;
  var flag=true;
  for(var i=1;i<=a;i++)
    {
      flag=true;
      for(var j=0;j<b.length;j++)
        {
          if(i>=b[j]&&flag)
            {
              f[i]=f[i-b[j]]+1;
              flag=false;
            }
          if(i>=b[j]&&(f[i-b[j]]+1<f[i]))
            {
              f[i]=f[i-b[j]]+1;
            }
        }
    }
  return f[a];
}
发表于 2020-04-03 12:17:50 回复(0)
#include <iostream>
using namespace std;
int n,m,dp[100001],temp,a[20];
int main(){
	while(cin>>n){
		for(int i=0;i<=100000;i++){
			dp[i]=-1;
		}
		if(n==0){
			break;
		}
		cin>>m;
		for(int i=0;i<m;i++){
			cin>>temp;
			a[i]=temp;
			if(temp<=n){
				dp[temp]=1;
			}
		}
		for(int i=0;i<=n;i++){
			for(int j=0;j<m;j++){
				if(a[j]<i&&dp[i-a[j]]!=-1){
					if(dp[i]==-1){
						dp[i]=dp[i-a[j]]+1;
					}
					else{
						dp[i]=min(dp[i],dp[i-a[j]]+1);
					}
					
				}
			}
		}
		if(dp[n]==-1){
			cout<<"Impossible"<<endl;
		}
		else{
			cout<<dp[n]<<endl;
		}
		
	}
	return 0;
}

发表于 2020-03-28 17:42:06 回复(0)
递归 超时...
function a(num,lines,n){
    if(arrRes.length==0 || n< Math.min(...arrRes)){
        for(var i=0;i<lines.length;i++){
            var n1 = n;
            if(num==lines[i]){
                n1++;
                arrRes.push(n1);
                n1--;
            }else if(num>lines[i]){
                n1++;
                a(num-lines[i],lines,n1);
            }
        }
        if(arrRes.length==0){
            minN = "Impossible"
        }else{
            minN = Math.min(...arrRes);
        }
    }else{
        return ;
    }
}
while(true){
    var arrRes=[];
    var num =parseInt(readline());
    if(num==0){
        break;
    }
    var lines = readline().split(" ");
    a(num,lines,0)
    var minN ;
    console.log(minN)
}
发表于 2020-03-27 15:54:19 回复(0)
//超时了...思路是先用若干可用的最大面额的代金券,再减去代金券抵扣的,递归求解剩下的金额的代金券方案。递归终止条件是可用的代金券面额都大于剩余的金额。
function calc(price, tickets) {
    if (price == 0 || tickets.lengh == 0) { return NaN; }
    tickets.sort((a, b) => b - a);
    for (let i = 0; i < tickets.length; ++i) {
        //忽略金额大于价格的代金券
        if (price < tickets[i]) { continue; }
        let amount = tickets[i];
        //价格是代金券的倍数
        if ((price % amount) == 0) { return price / amount; }
        if (i == tickets.lengh - 1) { return NaN; }
        //计算最多可能使用多少张当前金额代金卷
        let j = Math.floor(price / amount);
        //依次尝试,成功则记录代金券张数
        const cans = [];
        while (j >= 0) {
            let n = calc(price - amount * j, tickets.slice(i + 1));
            if (n) { cans.push(n + j); }
            --j;
        }
        cans.sort((a, b) => a - b);
        return cans[0] ? cans[0] : NaN;
        return NaN;
    }
}

while (true) {
    const price = parseInt(readline());
    if (!price) { break; }
    let s = readline();
    const tickets = s.trim().split(' ').slice(1);
    const n = calc(price, tickets);
    console.log(n ? n : 'Impossible');
}


编辑于 2020-03-26 23:22:31 回复(0)
c++
#include <iostream>
using namespace std;
 
int main(){
    int flag=1;
    while(flag){
        int cash;
        cin>>cash;
        if(cash==0){
            break;
        }
        int num;
        cin>>num;
        int *coins=new int[num];
        int count=0;
        int size=num;
        while(num--){
            cin>>coins[count];
            count++;
        }
        for(int p=0;p<size;++p){
            for(int q=0;q<size-p-1;++q){
                if(coins[q]>coins[q+1]){
                    swap(coins[q],coins[q+1]);
                }
            }
        }
        int *F=new int[cash+1];
        for(int i=0;i<=cash;++i){
            F[i]=cash+1;
        }
        F[0]=0;
        for(int j=0;j<=cash;++j){
            for(int k=0;k<size;++k){
                if(j<coins[k]){
                    break;
                }
                else{
                    F[j]=min(F[j-coins[k]]+1,F[j]);
                }
            }
        }
        if(F[cash]==cash+1){
            cout<<"Impossible"<<endl;
        }
        else{
            cout<<F[cash]<<endl;
        }
    }
}


发表于 2020-03-11 19:05:36 回复(0)