首页 > 代码库 > 装箱问题
装箱问题
一 问题分析
这次我听老范了讲了装箱的问题,题目:有n个物品,体积为v1,v2,v3. . .然后要求用最少的箱子把这些物品里面,这个是基于贪心算法的思想。贪心算法呢,就是每次找到的都是当前最优的,但是最后从总体情况看,它不一定是最优的;贪心算法规则一旦建立,就不能更改。一般情况下贪心算法求的解都是最优解。、
我们先对物品进行从大到小进行排序,每次拿出一个物品从第一个箱子开始遍历,如果可以放下,那么重新拿出一个物品在从第一个开始遍历,如果放不下,那么我们就开一个新箱子,将这个物品放在里面。其实这个思想很简单的,最简单的说我每一次拿出一个物品都是从第一个箱子开始,放的下,拿下一个物品,放不下,开新箱子,每次遍历的是箱子。
还有一种思路呢,就是每次遍历的是物品。意思就是呢,我拿出一个箱子,开始遍历物品(物品体积都是从大到小),遍历完一次物品后第一个箱子就表示装满了,然后在开辟第二个箱子,知道所有的物品装完为止。
存储 : 对于物品个数我们是固定的的,可以用数组来存放。而对于箱子呢,我们不知道到底要用多少个箱子,因此呢箱子的个数我们用链表去存放。每个箱子里面装的物品个数也不确定,那么也用链表来处理。我们可以用3个结构体,第一个结构体箱子信息,第二个结构体物品信息,第三个结构体箱子中的物品的信息
二 代码区
#include <iostream> #include<stdlib.h> #define null NULL #define V 10 typedef struct{ //物品信息的结构体 int go; //编号 int gv; //体积 }GOODS; typedef struct Gnode{ // 物品节点 int gnum; // 挂在链上的编号 struct Gnode *link; //指向下一个物品节点 }GNODE; typedef struct Gbox{ // 箱子结构体 int reminder; //剩余空间 GNODE *head; // 指向物品节点的第一个节点 struct Gbox *next; }GBOX; void sortvolume(GOODS *goods,int n){ //排序 int i,j; GOODS t; for(i=0;i<n-1;i++) for(j=i;j<n;j++) if(goods[i].gv<goods[j].gv) { t=goods[i]; goods[i]=goods[j]; goods[j]=t; } } GBOX *packingbox(GOODS *goods,int n){ //具体实现装箱 int i; GBOX *hb=null,*ht,*p; GNODE *newg,*q; for(i=0;i<n;i++){ newg=(GNODE*)malloc(sizeof(GNODE)); newg->gnum=goods[i].go; newg->link=null; for(p=hb;p&&p->reminder<goods[i].gv;p=p->next); //p停下来时一定的总是开辟新箱子,分号注意 if(!p) { p=(GBOX *)malloc(sizeof(GBOX)); p->head=null; p->next=null; p->reminder=V; if(!hb) hb=ht=p; else ht=ht->next=p; } p->reminder-= goods[i].gv; for(q=p->head;q&&q->link;q=q->link);// 特别注意 if(!q) p->head=newg; else q->link=newg; } return hb; } void printpackingbox(GBOX *hbox) //输出 { GBOX *p; GNODE *q; int i=0; for(p=hbox;p;p=p->next) { printf("这是第%d个箱子,里面有",++i); for(q=p->head;q;q=q->link) { printf("编号为%d",q->gnum); } printf("\n"); } } int main(int argc, char** argv){ //主函数 int n; GOODS *goods; GBOX *hbox; printf("请你输入物品的个数: "); scanf("%d",&n); goods=(GOODS *)malloc(n*sizeof(GOODS)); for(int i=0;i<n;i++){ printf("输入第%d个物品的体积是",i+1); scanf("%d",&goods[i].gv); goods[i].go=i+1; } sortvolume(goods,n); hbox=packingbox(goods,n); //箱子的头结点 printpackingbox(hbox); //输出 return 0; }
三 示意图
箱子挂上物品后就是这个样子
四 分析代码
现在有很多 排序方法,选择,插入,快排,冒泡,归并随便写一个就好。
这个程序有几处特别好,不知道你们看没有看出来,2个for语句循环里面是空的,for(p=hb;p&&p->reminder<goods[i].gv;p=p->next); 这个分号特别注意,不管我开不开新箱子,我总会用一个p指针来处理箱子的问题,而p停的地方就是当前这个物品一定可以放进去的,如果p为空。我就开新箱子放,如果p不为空,直接放进去。应用同样的思路,我就只用一个q指针很好的处理了装在箱子里面的物品链,不管头不为空。q停下的地方一定可以把该物品挂在后面,for(q=p->head;q&&q->link;q=q->link);(分号特别注意)我利用了尾插法,有人会问为什么不用头插法,原因是虽然这样好处理,但是这样物品就被倒着放在里面了。
这次我还知道了,尽可能使for循环里面嵌套if else 不要在if else 里面嵌套for循环,因为一般是大时间复杂度嵌套小的。
五 运行结果
注意箱子设的最大体积是10,不可以超过10
如果里面有什么错误,或者什么建议,欢迎大家提出来
装箱问题