首页 > 代码库 > 装箱问题

装箱问题

   一  问题分析   

       这次我听老范了讲了装箱的问题,题目:有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

 

      

        如果里面有什么错误,或者什么建议,欢迎大家提出来

         

装箱问题