装箱问题(贪婪策略:首次适应递减(First Fit Decreasing, FFD))

本文介绍了装箱问题及其解决方法,利用贪婪策略中的首次适应递减(FirstFitDecreasing,FFD)算法,通过物品体积降序排列和动态调整箱子容量来达到最少箱子数目的目标。同时,文章提到了代码实现、排序方法以及注意事项,包括内存管理的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装箱问题(贪婪策略:首次适应递减(First Fit Decreasing, FFD))

装箱问题是一种典型的组合优化问题,它可以用多种贪婪(greedy)策略来解决。贪婪算法通过在每一步选择当前最优的解决方案,希望这样会导致全局最优解。

问题描述:假设有编号分别为0,1,…,n-1的n种物品,体积分别为V0,V1,…,Vn-1。将这n种物品装到容量都为V的若干箱子里。约定这n种物品的体积均不超过V,即对于0≤ i<n,有0<Vi ≤V。不同的装箱方案所需要的箱子数目可能不同。“装箱”问题要求用尽量少的箱子装下这n种物品。

代码如下:

//装箱问题
#include <stdio.h>
#include <malloc.h>
#define V 10 //一个箱子所能装的最大体积
 //物品信息
typedef struct 
{
     int gnum; //物品编号
     int gv; //物品体积
}Goods;

//物品链
typedef struct Node
{
      int gnum;
      struct Node *next; //连接下一个物品
}GoodsLink;

//箱子链
typedef struct Box
{
      int bv; //箱子体积
      struct Box *next; //下一个箱子
      struct Node *hg; //箱子上的物品节点
}BoxLink;

//物品体积降序排列
//冒泡排序法进行排序
Goods *SortGoods(Goods *g,int n) 
{
      for(int i=0;i<n-1;i++)
      {
           for(int j=0;i+j<n-1;j++)
           {
	 if(g[j+1].gv>g[j].gv)
	 {
 	      Goods t=g[j];
                      g[j]=g[j+1];
 	      g[j+1]=t;
                 }
           }
      }
      return g;
}

//装箱
BoxLink *CreateBoxLink(Goods *g,int n)
{
     GoodsLink *pg,*qg;
     BoxLink *pbox,*hbox=NULL,*t;
     for(int i=0;i<n;i++)
     {
            //创建物品节点
            pg=(GoodsLink *)malloc(sizeof(GoodsLink));
            pg->gnum=g[i].gnum;
            pg->next=NULL; 
           //判断是否需要创建新的箱子节点
           //判断条件:箱子结点不为空&&该物品的体积大于箱子所剩余的体积
           for(pbox=hbox;pbox&&(pbox->bv<g[i].gv);pbox=pbox->next); 
               //如果没有找到合适的箱子创建箱子节点
               if(!pbox)
               {
 	     //创建新的箱子节点
	     pbox=(BoxLink *)malloc(sizeof(BoxLink));
 	     pbox->bv=V;
 	     pbox->hg=NULL;
 	     pbox->next=NULL;
                     if(!hbox) //判断箱子链表是否为空
	           hbox=t=pbox;
	     else
 	           t=t->next=pbox; 
                } 
              //不执行if:表示有箱子可以放的下物品
           pbox->bv-=g[i].gv;          //用剩余箱子体积减去当前的物品体积
           if(!pbox->hg)                  //在当前箱子上挂物品,判断箱子上是否有物品
 	pbox->hg=pg;          //该物品是这个箱子的第一个物品节点
           else 
           {
 	for(qg=pbox->hg;qg->next;qg=qg->next);          //找到挂物品所要挂的位置
 	     qg->next=pg;             //将物品挂在找到的节点上
           }
 
      }
      return hbox;
}

 //输出每个箱子所装的物品
void PrintBox(BoxLink *hbox)
{
      int cnt=0;
      for(BoxLink *pbox=hbox;pbox;pbox=pbox->next)
      {
           printf("第%d个箱子所放的物品编号:",++cnt); 
           for(GoodsLink *pg=pbox->hg;pg;pg=pg->next)
 	printf("%2d",pg->gnum); 
           printf("\n"); 
      }
      printf("\n");
} 

int main(void)
{
     int n,v;
     Goods *g;
     BoxLink *hbox;
     printf("请输入物品的个数:");
     scanf("%d",&n);
     printf("\n");
     g=(Goods *)malloc(n*sizeof(Goods)); //定义物品信息
      //初始化物品信息
      for(int i=0;i<n;i++)
      {
             printf("请输入第%d件物品体积: ",i+1);
             scanf("%d",&v);
             g[i].gv=v;
             g[i].gnum=i+1;
      }
      printf("\n");
      g=SortGoods(g,n); //物品体积降序排列
      hbox=CreateBoxLink(g,n); //装箱
      PrintBox(hbox); //输出每个箱子所装的物品
      return 0 ;
}
总体流程
  1. 输入物品信息:首先获取物品个数和每个物品的体积,并将它们存储在一个结构体数组中。
  2. 物品排序:然后对物品按体积进行降序排列,使得大物品优先被处理。
  3. 装箱:根据物品的大小和箱子的剩余容量来决定物品的放置。
  4. 输出结果:最后打印出每个箱子中包含的物品编号。
关键组件
  • 物品(Goods):包括物品编号gnum和物品体积gv的结构体。
  • 物品链(GoodsLink):用于链表形式存储每个箱子内的物品编号。
  • 箱子链(BoxLink):表示每个箱子,包含该箱子剩余体积bv、指向下一个箱子的指针next和指向该箱子内第一个物品节点的指针hg
详细解释
物品体积降序排列 SortGoods

使用冒泡排序算法对物品按体积进行降序排列。这样做的目的是尽可能优先处理大物品,便于后续的装箱操作。

装箱 CreateBoxLink
  1. 遍历每个物品,为其创建一个物品链节点。
  2. 尝试找到一个可容纳当前物品的箱子(箱子的剩余体积足够大)。
    • 如果找到合适的箱子,则更新箱子的剩余体积,并将该物品节点加入箱子的物品链中。
    • 如果没有找到合适的箱子,则新建一个箱子,并将其加入箱子链中,然后重复上述步骤。
  3. 这个过程采用贪心策略,尽量在已有的箱子中放置物品,以减少总箱子数。
输出结果 PrintBox

遍历箱子链,对于每个箱子,打印出其中包含的所有物品编号。这显示了每个箱子中物品的装载情况。

注意事项
  • SortGoods函数中,循环条件有误:for(int j=0;i+j<n-1;j++)应改为for(int j=0;j+i<n-1;j++),否则会造成无限循环或跳过排序。
  • 使用malloc分配内存时需要注意内存管理,确保在使用完毕后释放已分配的内存,避免内存泄漏。本代码未展示内存释放过程。

如果觉得文章对您有帮助,请帮忙点赞或者收藏,如果在文章中发现什么错误或不准确的地方,欢迎与我交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

5-StarrySky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值