問題
某糖果公司專門生產兒童糖果,它最受兒童歡迎的糖果有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);
}
}
}
轉載請註明本網頁,多謝。