您的位置:首页 > 编程语言

编码-京东实习笔试编程题-糖果问题-动态规划

2016-04-13 23:10 525 查看
问题

某糖果公司专门生产儿童糖果,它最受儿童欢迎的糖果有A1、A2两个序列,均采用盒式包装。包装好的A1类糖果体积为一个存储单位,而包装好的A2类糖果体积正好是A1类的两倍。

这两类糖果之所以广受儿童欢迎,是因为糖果中含有公司独家研发的魔幻因子。A1或A2序列中的糖果,看起来包装可能是一样的,但因为其中的魔幻因子含量不同被细分为不同的产品。

临近传统节日,公司的糖果供不应求。作为一个精明的糖果分销商,小东希望能够借此大赚一笔,于是带着现金开着货车来公司提货。货车的容量是确定的,小东希望采购的糖果能够尽可能装满货车,且糖果的魔幻因子总含量最高。只要不超出货车容量,糖果总可以装入货车中。

小东希望你能帮她解决这一问题。

输入

输入中有多组测试数据。每组测试数据的第一行有两个整数n和v,1<=n<=10^5, 1<=v<=10^9,n为可供选购糖果数量,v为货车的容量。随后n行为糖果的具体信息,第一行编号为1,第二行编号为2,以此类推,最后一行编号为n。每行包含两个整数ti和pi,1<=ti<=2, 1<=pi<=10^4,ti为糖果所属的序列,1为A1、2为A2,pi则是其中的魔幻因子含量。

输出

对每组测试数据,先在单独的一行中输出能采购的糖果中的魔幻因子最高含量,之后在单独的行中按编号从小到大的顺序输出以空格分隔的糖果编号,若有多组糖果组合均能满足要求,输出编号最小的组。若没有糖果能够满足要求,则在第一行中输出0,第二行输出“No”。

样例输入

3 2

1 2

2 7

1 3​

样例输出

7

2​

解题思路

通常是用0-1背包问题的解法来做,楼主自己想到了一种比较好的,复杂度为nlgn的方法,测试后发现算法运行时间为经典解法的一半。

具体思路:

分别获取不同空间的列表,并对其排序。先填充2空间的糖果,直到糖果用完或者空间快满,然后用1空间的糖果填充剩余空间。

之后,比较两个1空间的糖果和一个2空间的糖果魔法因子哪个更大,分别进行相应的替换。具体代码如下:(楼主 使用了Java代码,各位可以用其他代码进行尝试)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

public class CandyProblem {

public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextInt()){
int nums = scanner.nextInt();
int sumPlace = scanner.nextInt();
int[][] singleNum = new int[nums][2];
int[][] doubleNum = new int[nums][2];
for (int i = 0; i < nums; i++) {
int space=scanner.nextInt();
if (space==1) singleNum[i]=new int[]{scanner.nextInt(),i+1};
else doubleNum[i]=new int[]{scanner.nextInt(),i+1};
}
findNum(singleNum,doubleNum,sumPlace,nums);
}
}

public static void findNum(int[][] singleNum, int[][] doubleNum, int sumPlace, int nums) {
Arrays.sort(singleNum,new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[0]<o2[0]) return 1;
else if (o1[0]>o2[0]) return -1;
else return 0;
}
});
Arrays.sort(doubleNum,new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[0]<o2[0]) return 1;
else if (o1[0]>o2[0]) return -1;
else return 0;
}
});
if(sumPlace<1) System.out.println(0+"\n"+new ArrayList<>());
else if(sumPlace==1) {
List<Integer> list = new ArrayList<>();
list.add(singleNum[0][1]);
System.out.println(singleNum[0][0]+"\n"+list);
}
else {
List<Integer> list = new ArrayList<>();
int sum = 0;
int doublenum = 0;
for (int i = 0; i<nums && 2*doublenum<sumPlace-1; i++) {
if (doubleNum[i][0]==0) break;
list.add(doubleNum[i][1]);
sum += doubleNum[i][0];
doublenum++;
}
int singlenum = 0;
//如果数组未满,则进行补全
if (doublenum*2<sumPlace) {
for (int i = 0; i <nums && doublenum*2+singlenum<sumPlace; i++) {
list.add(singleNum[i][1]);
sum += singleNum[i][0];
singlenum++;
}
}
//在数组满后,用临近的两个1容量的替换一个2容量的
while(doublenum>0 && nums-singlenum-2>=0) {
if (singleNum[singlenum][0]+singleNum[singlenum+1][0]>doubleNum[doublenum-1][0]) {
list.remove((Object)doubleNum[doublenum-1][1]);
sum -= doubleNum[doublenum-1][0];
list.add(singleNum[singlenum][1]);
sum += singleNum[singlenum][0];
list.add(singleNum[singlenum+1][1]);
sum += singleNum[singlenum+1][0];
singlenum+=2;
doublenum--;
}
else break;
}
System.out.println(list);
System.out.println(sum);
}
}
}


转载请注明本网页,多谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息