贪心算法解装箱问题

问题描述

有N个物品,其重量大小为W,其取值范围为0<W<=V,有一批容量为V的箱子,问最少需要多少个箱子可以把这些物品装上。

思路

利用回溯和减枝是肯定可以的,毕竟是一种穷举。也可以利用动态规划方法来解决。本题主要讨论贪心算法的解决方法,其主要思想是每次选择都选择最优的,即让箱子每次都装能让箱子承受的住的最大重量,若遍历所有物品都没有能让箱子承受的住的,则换下一个箱子来装。其主要思想就跟有一张整的纸币,要将其换成10元,5元,1元的纸币,要求是换出的纸币的数量最少一样,那肯定是先从面值大的纸币换,换不了了再从面值次之的去换以此下去。
eg:

比如有5个物品其重量分别是 40 50 50 60 70 箱子的最大容量为100
则第一个箱子首先选择70,由于再没有其它的物品能供它装,换第二个箱子
第二个箱子首先装60,遍历后的最优为40,所以再装40,此时箱子的容量已满
换下一个箱子,第三个箱子首先选择50,然后遍历的最优为50
此时物品也已选择完,结束。所以所选择的最少箱子数量为三个。(ps:每个物品被选择后不再遍历它)

代码如下

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define V 100	//允许箱子能装的最大容积
#define N 5	//物体的数量

typedef struct {
	int number;//物体编号
	int volume;//物体容积
	_Bool flag1;//表示物品是否被装入
}object;

typedef struct{
	int memory[N];//装了啥物品,最多装N个
	int installed_capacity;//已装容量之和
	int surplus_capacity;//剩余容量
	_Bool flag;//标志表示该物品是否被用
}box;
//void mysort(object a[],int N);
void init(box*b){ //初始化函数
	b->flag=false;
	b->installed_capacity=0;
	b->surplus_capacity=V;
	int i;
	for(i=0;i<N;i++){
		b->memory[i]=0;
	}
}
void init_(object*b){//初始化函数,初始化箱子
	b->flag1=true;
	b->number=0;
	b->volume=0;
}
void mysort(object a[]){//排序,利用选择排序,有空写个快速排序
	int i,j;
	for(i=1;i<=N-1;i++){
		for(j=i;j<=N;j++){
			if(a[i].volume<a[j].volume){
				int temp1=a[j].number;
				int temp2=a[j].volume;
				a[j].number=a[i].number;
				a[j].volume=a[i].volume;
				a[i].number=temp1;
				a[i].volume=temp2;
			}
		}
	}
}
void myqsort(object a[],int begin ,int end){//快速排序方法
        if(begin<end){
            int key=a[begin].volume;
            int keynumber=a[begin].number;
            int i=begin;
            int j=end;
            while(i<j){
                while(i<j&&a[j].volume<key){
                    j--;
                }
                if(i<j){
                    a[i].number=a[j].number;
                    a[i].volume=a[j].volume;
                    i++;
                }
                while(i<j&&a[i].volume>key){
                    i++;
                }
                if(i<j){
                    a[j].number=a[i].number;
                    a[j].volume=a[i].volume;
                }
            }
            a[i].volume=key;
            a[i].number=keynumber;
            myqsort(a,begin,i-1);
            myqsort(a,i+1,end);
        }
}
int main(void){
	object *o=(object*)malloc(sizeof(object)*(N+1));
	int i;
    printf("请分别输入这%d物品的编号和重量:\n",N);
	for(i=1;i<=N;i++){
		//o[N].number=i;
		init_(&o[i]);
		scanf("%d%d",&((&o[i])->number),&((&o[i])->volume));//输入各物品的编号和容量
		(&o[i])->flag1=true;//此时表示此物品并未被使用
	}
	//box b[N];//利用realloc估计更好
    box*b=NULL;
	/*for(i=0;i<N;i++){
		init(&b[i]);
	}*/
	//mysort(o);
    myqsort(o,1,N);//快速排序。非递增排序
	int count=N;
	int num=0;//箱子数量
	int j;
	while(count){
        num++;
        b=(box*)realloc(b,sizeof(box)*num);
        init(&b[num-1]);
        int k=0;
		for(j=1;j<=N;j++){
			if(o[j].flag1==true&&b[num-1].surplus_capacity>=o[j].volume){
				b[num-1].installed_capacity+=o[j].volume;
				b[num-1].surplus_capacity-=o[j].volume;
				o[j].flag1=false;
				b[num-1].flag=true;
				b[num-1].memory[k++]=o[j].number;
				count--;//箱子被选就减一
			}
		}
	}
	printf("所用的箱子数量为%d\n",num);
    for(int i=0;i<num;i++){
        printf("第%d只箱子所装的物品编号为:\n",i+1);
        for(int j=0;j<N;j++){
            if(b[i].memory[j]==0){
                break;
            }
            printf("%d ",b[i].memory[j]);
            
        }
        printf("\n");
    }
    free(b);//当用完之后记得释放内存
    free(o);
    getchar();
    getchar();
	return 0;
    

	
}

其结果如下:
在这里插入图片描述

后言

很显然的是,利用贪心算法并不能总是得到最优解。相比较之下利用回溯和动态规划可以真正得到最优解。但其时间复杂度也必然会大大增加。(ps:有时间试试出一篇回溯或者动态规划的题解)
以上
end

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐