其实,这是一篇试水文…
PART I - 前言
上次的代码有BUG,这次的代码合理不会有BUG(除非溢出)。 这道题竟然出现在校内OJ平台上的提前练手区域(1300 Problem)!简直过分!自我感觉这已经达到了ACM新手入门水平的题目了_(:з)∠)_ 所以因为这道题,原本要发的SZU OJ题组1、2就留到下一次吧 ╮( ̄▽ ̄”)╭ 那天同级的高大佬和我讨论思路,根据他提供的思路我写出这次的代码,谢谢高大佬!
PART II - 题目
- 题目来源
BJC - 题目描述
N个集装箱要装上1艘载重量为c的轮船,其中第i个集装箱的重量为wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。可以使用贪心算法、穷举法等。 - 输入
第一行输入N和C,表示集装箱数量和轮船的载重,第二行输入N个集装箱的重量。 - 输出
约定长为N的01字符串(1:表示装)以字典序最大的那个为符合要求的装载方案。 - 样例输入
3 50
40 10 40 - 样例输出
110
PART III - 思路
①排序
题目要求“将尽可能多的集装箱装上轮船”,即按集装箱的重量从小到大装入轮船内。因此,可先进行重量升序排序。
②贪心
开始按从轻到重的顺序填轮船,因为已经排序,所以是按数组从[0]开始填轮船,装到不能再装后,记录装载个数。
③ 穷举
以上面的图为例,可知输出结果的最大字典序为111110000000000(即排在前面的都被装载),最小字典序为000000000011111(即排在最后面的都被装载)。 将他们看作二进制数,那么将最大字典序设为起点,判定是否满足刚好存在5个’1’,’1’对应的集装箱重量之和是否不超过轮船可承载总重量。如果是,那么当前组合满足条件,输出结果;如果不是,则减1(因为减1能满足次最大字典序的要求),再次循环,直到满足条件为止。
由于无法直接使用二进制数计算,因此先将最大/最小字典序转换为十进制数(即31744和31),进行计算时转化为模拟二进制数字符数组,再进行上述操作。(当然也可以写一个类或者功能模拟二进制数运算)
PART IV - 源代码
//最优装载问题(贪心 + 穷举)
#include "iostream"
#include "cstdio" //C++下写C代码,故用 cstdio
#include "algorithm" //使用sort()函数
#include "malloc.h" //动态分配数组内存
#include "cmath" //使用pow()函数
void toBinary(char* array,int end, int nBox){ //十进制转二进制数组
for(int n = nBox - 1; n >= 0; n--){
array[n] = end%2 + '0';
end /= 2;
}
}
int main(){
int weight; //可承载重量
int nBox; //集装箱个数
int maxNums = 0; //按照从轻到重的顺序放置集装箱,可承载的最大数量
scanf("%d%d", &nBox, &weight);
int* arrayInput = (int*)malloc(nBox*sizeof(int));
int* arrayInputUpper = (int*)malloc(nBox*sizeof(int));
for(int n = 0; n < nBox; n++){
scanf("%d", &arrayInput[n]);
arrayInputUpper[n] = arrayInput[n];
}
std::sort(arrayInputUpper, arrayInputUpper + nBox);
int temp = weight;
for(int n = 0; n < nBox; n++){ //贪心,确定最大数量maxNums
temp -= arrayInputUpper[n];
if(temp >= 0){
maxNums++;
}else{
break;
}
}
int start = pow(2, maxNums) - 1; //等比数列公式,下同
int end = pow(2, nBox - maxNums)*(pow(2, maxNums) - 1);
char* arrayRange = (char*)malloc(nBox*sizeof(char));
for(;start <= end; end--){
int times = 0;
int temp = 0;
toBinary(arrayRange, end, nBox);
arrayRange[nBox] = '\0';
for(int n = 0; n < nBox; n++){ //是否出现maxNums次1
if(arrayRange[n] == '1'){
times++;
}
}
if(times != maxNums){
continue;
}
for(int n = 0; n < nBox; n++){ //和是否不超过weight
if(arrayRange[n] == '1'){
temp += arrayInput[n];
}
}
if(temp <= weight){
break; //满足结果跳出循环
}else{
continue;
}
}
printf("%s", arrayRange);
free(arrayInput);
free(arrayInputUpper);
free(arrayRange);
return 0;
}