题目描述
某商场有 N 件商品,其中第 i 件的价格是 Ai。现在该商场正在进行 “买二赠一” 的优惠活动,具体规则是:
每购买 2 件商品,假设其中较便宜的价格是 P(如果两件商品价格一样,则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P/2的商品,免费获得这一件商品。可以通过反复购买 2 件商品来获得多件免费商品,但是每件商品只能被购买或免费获得一次。
小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?
输入格式
第一行包含一个整数 N。
第二行包含 N 个整数,代表 A1, A2, A3, . . . ,AN。
输出格式
输出一个整数,代表答案。
样例输入
7
1 4 2 8 5 7 1
样例输出
25
————————————————
官方题解的贪心思路: 6
12 23 25 25 50 50
这个测试是错误的,讨论区一位友友写的具象化,这题用贪心的确不太合适,不然就得改
我的代码测试是正确的,但是只能通过70%的测试用例,剩下的30%超时
官方题解的代码,上述测试用例测出来是160,我自己的代码测出来是150,50+50送23,25+25送12,50+50+25+25=150
思路:每次买两个商品都取最大价格的赠品
package Mai2Song1;
import java.util.Arrays;
import java.util.Scanner;
public class Mai2Song1 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int minprice = 0;
int n = scan.nextInt();
if (n < 0) {
System.out.println(0);
scan.close();
return;
}
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scan.nextInt();
}
if (n < 2) {
minprice += arr[0] + arr[1];
System.out.println(minprice);
scan.close();
return;
}
reverseSort(arr);// 逆序排序
int len = arr.length;
int i = 0;
for (i = 2; i < len;) {// 从第三个商品开始检索,从大到小判断商品是否可以作为赠送品
int j = i - 1;// 判断是否为赠送品,与之判断的首个就是它的前一个商品
while (j >= 1) {// 不能跟第一个商品比较,因为条件是不超过较低价钱商品的1/2,所以最贵的商品的价格除2也不能作为赠品
int curtem = arr[j] / 2;
if (curtem >= arr[i]) {// i位置的商品低于j位置商品价格的1/2,可作为赠送品
minprice += arr[j-1] + arr[j];// 买第一个商品跟第j个商品,再把它们赋值为0
arr[j-1] = 0;
arr[j] = 0;
arr[i] = 0;// 为赠品
i -= 2;
reverseSort(arr);// 再次排序,已经购买了赠送了的商品价格赋值为0放到数组后面
// 这里的重复排序可以用一个新数组替代
// newarr = arr[3-n];//具体写法自己琢磨
break;
}
j--;// 前一个商品的价格不能使i商品作为赠品,则j--继续判断前一个,直到第2个最贵的商品
// 如果也不能,则说明i商品只能作为购买的商品,不能作为赠品
}
if (j == 0) {// 说明i不能作为赠品
i++;
}
while (i < 2) {// 确保i商品,前面有两个价格更高的商品
i++;
}
if (i >= n || arr[i] == 0) {// 此时剩余的商品都不满足赠送条件了,只能全部原价购买了
break;
}
}
for (int j = 0; j < i; j++) {
minprice += arr[j];
}
System.out.println(minprice);
scan.close();
}
public static void reverseSort(int[] arr) {
Arrays.sort(arr);
int len = arr.length - 1;
for (int i = 0; i < (len + 1) / 2; i++) {
int temp = arr[len - i];
arr[len - i] = arr[i];
arr[i] = temp;
}
}
}