【备战秋招】每日一题:2022.9.21-华为机试-年会奖品分配策略

为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接:P1031

题目内容

塔子哥的公司准备在年会上开展抽奖活动。他们购买了若干个奖品,每个奖品都有一个价格,用一个正整数数组表示。在抽奖环节,公司准备设置一等奖、二等奖和三等奖,每个等级设置一个奖品,并将所有奖品分成三份大礼包。公司希望尽可能地减小一等奖和三等奖之间的价格差异,同时满足一等奖总价格大于二等奖总价格,二等奖总价格大于三等奖总价格。

为了实现这一目标,公司需要找到一种合适的分配方案。具体来说,假设一等奖总价格为 x x x,二等奖总价格为 y y y,三等奖总价格为 z z z,则 x > y > z > 0 x>y>z>0 x>y>z>0。同时,假设奖品的总数量为 n n n,用正整数数组 a r r a y array array 表示每个奖品的价格。

现在的问题是塔子哥他们不知道如何分配奖品,才能使得一等奖和三等奖之间的价格差最小,你能帮帮他们吗?

输入描述

第一行:正整数 n n n ,表示奖品的数量,取值范围 [ 3 , 16 ) [3,16) [3,16)

第二行:一个正整数数组 a r r a y array array ,每个元素表示奖品的价格,取值范围 [ 1 , 1000 ] [1,1000] [1,1000]

输出描述

一个非负整数,表示一等奖和三等奖的差值,没有方案返回 0 0 0

样例

样例一:

输入

3
5 4 2

输出

3

样例解释

分配方案只有一种 5 , 4 , 2 {5,4,2} 5,4,2

样例二:

输入

4
10 5 4 2

输出

5

样例解释

分配方案有 10 , 9 , 2 {10,9,2} 10,9,2 10 , 7 , 4 {10,7,4} 10,7,4 10 , 6 , 5 {10,6,5} 10,6,5 15 , 4 , 2 {15,4,2} 15,4,2 14 , 5 , 2 {14,5,2} 14,5,2 12 , 5 , 4 {12,5,4} 12,5,4

一等奖和三等奖差值最小的方案是 10 , 6 , 5 {10,6,5} 10,6,5

题目思路

这道题可以很暴力的用 d f s dfs dfs暴搜解决。首先,我们用 a r r [ i ] arr[i] arr[i]表示第 i i i个奖品的金额。 d f s ( t a r , s u m x , s u m y , s u m z ) dfs(tar, sumx, sumy, sumz) dfs(tar,sumx,sumy,sumz),其中 t a r tar tar表示我们枚举到了 a r r [ t a r ] arr[tar] arr[tar],然后就是选择将这个奖品放在哪一个盒子里。 d f s dfs dfs中后面三个参数 s u m x , s u m y , s u m z sumx, sumy, sumz sumx,sumy,sumz就是表示三个盒子目前的金额数量。所以如果我们对于第 t a r tar tar个物品,选择放进第一个盒子里,那么就是 d f s ( t a r + 1 , s u m x + a r r [ t a r ] , s u m y , s u m z ) dfs(tar+1,sumx+arr[tar],sumy,sumz) dfs(tar+1,sumx+arr[tar],sumy,sumz)。同理,放在第二个和第三个分别是 d f s ( t a r + 1 , s u m x , s u m y + a r r [ t a r ] , s u m z ) dfs(tar+1,sumx,sumy+arr[tar],sumz) dfs(tar+1,sumx,sumy+arr[tar],sumz) d f s ( t a r + 1 , s u m x , s u m y , s u m z + a r r [ t a r ] ) dfs(tar+1,sumx, sumy, sumz+arr[tar]) dfs(tar+1,sumx,sumy,sumz+arr[tar])

d f s dfs dfs除了递归的状态转移是一个重点,还有就是 d f s dfs dfs递归停止时的条件。这里 d f s dfs dfs停止的条件很明显就是 t a r = = n + 1 tar==n+1 tar==n+1,表示我们已经没有物品枚举了。然后当我们 d f s dfs dfs结束后,我们需要统计满足要求的答案,也就是要 s u m x > s u m y > s u m z > 0 sumx>sumy>sumz>0 sumx>sumy>sumz>0的答案。最后取最小值就行。

由于我们一共有15个奖品,每个奖品都选三个盒子,那么复杂度就是 O ( 3 15 ) O(3^{15}) O(315)

代码

Java代码

import java.util.Scanner;

public class Main {
    static int n;
    static int[] arr = new int[16];
    static int minn = Integer.MAX_VALUE;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);//输入
        n = input.nextInt();
        for(int i = 1; i <= n; i++){
            arr[i] = input.nextInt();
        }
        dfs(1, 0, 0,0);
        if(minn == Integer.MIN_VALUE) System.out.println(0);//如果minn没更新过,说明没有合理的分法,那么就输出0
        else System.out.println(minn);

    }
    static void dfs(int tar, int sumx, int sumy, int sumz){
        if(tar == n + 1){//dfs终止条件
            if(sumx > sumy && sumy > sumz && sumz > 0){
                minn = Math.min(minn, sumx - sumz);
            }
            return;
        }//下面三个dfs分别表示第tar物品,放进哪个盒子
        dfs(tar + 1, sumx + arr[tar], sumy, sumz);
        dfs(tar + 1, sumx, sumy + arr[tar], sumz);
        dfs(tar + 1, sumx, sumy, sumz + arr[tar]);
    }
}

C++代码

#include <iostream>
#include <algorithm>
using namespace std;
int n;
int arr[16];
int minn = 2e9;
void dfs(int tar, int sumx, int sumy, int sumz) {
	if (tar == n + 1) { //dfs终止条件
		if (sumx > sumy && sumy > sumz && sumz > 0) {
			minn = min(minn, sumx - sumz);
		}
		return;
	}//下面三个dfs分别表示第tar物品,放进哪个盒子
	dfs(tar + 1, sumx + arr[tar], sumy, sumz);
	dfs(tar + 1, sumx, sumy + arr[tar], sumz);
	dfs(tar + 1, sumx, sumy, sumz + arr[tar]);
}
int main() {
	cin>>n;
	for (int i = 1; i <= n; i++) {
		cin>>arr[i];
	}
	dfs(1, 0, 0, 0);
	if (minn == (int)2e9) cout<<0<<endl; //如果minn没更新过,说明没有合理的分法,那么就输出0
	else cout<<minn<<endl;
	return 0;
}

Python代码

def dfs(tar,sumx,sumy,sumz):
	global minn
	if (tar == n + 1):#dfs终止条件
		if (sumx > sumy and sumy > sumz and sumz > 0): 
			minn = min(minn, sumx - sumz);
		return;
	#下面三个dfs分别表示第tar物品,放进哪个盒子
	dfs(tar + 1, sumx + arr[tar], sumy, sumz);
	dfs(tar + 1, sumx, sumy + arr[tar], sumz);
	dfs(tar + 1, sumx, sumy, sumz + arr[tar]);

arr=[0 for i in range(16)]
minn = int(2e9);
n=int(input())
arr=list(map(int,input().split()))
arr.insert(0,0)
dfs(1,0,0,0)
if minn==int(2e9):#如果minn没更新过,说明没有合理的分法,那么就输出0
	print(0)
else:
	print(minn)

Js代码

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';

process.stdin.on('data', (data) => {
	input += data;
	return;
});
process.stdin.on('end', () => {
    function dfs(tar,sumx,sumy,sumz){
        if (tar == n + 1) { //dfs终止条件
            if (sumx > sumy && sumy > sumz && sumz > 0) {
                minn = Math.min(minn, sumx - sumz);
            }
            return;
	   }//下面三个dfs分别表示第tar物品,放进哪个盒子
        dfs(tar + 1, sumx + arr[tar], sumy, sumz);
        dfs(tar + 1, sumx, sumy + arr[tar], sumz);
        dfs(tar + 1, sumx, sumy, sumz + arr[tar]);
    }
    let minn = Number(2e9);
    input=input.split('\n');
    var n=Number(input[0][0]);
    var arr=new Array();
    for (let i=1;i<=n;i++)
        arr[i]=Number(input[1].split(' ')[i-1]);
    dfs(1, 0, 0, 0);
	if (minn == 2000000000) console.log(0); //如果minn没更新过,说明没有合理的分法,那么就输出0
	else console.log(minn);
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值