为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接: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);
});