装箱问题之贪心算法

贪心准则:

  将问题的每一步抽象出一个公共的最优解。

  注意:在一步中不一定能找到最优解

优点

  简单快速,容易想清楚问题

问题描述:

有n和物品,每个物品体积v1, v2, v3……大小不一,但是都小于箱子体积大小V,现在将所有物品都打包装进箱子,要求装完这些物品之后打开的箱子数量尽量小,求打开的箱子数量是多少?

思路:

1.将所有物品按照体积大小降序排列

2.按照箱子打开的顺序,每一次从头遍历箱子结点,看打开的箱子的剩余体积能不能放下当前物品,直到遍历完所有已经打开的箱子还是放不下,就打开一个新的箱子。

图示展示:

运行结果:

代码描述:

#include <stdio.h>
#include <stdlib.h>
#define GOODS_COUNT  10		//定义物品的数量 
#define BOX_VOLUME 20		//定义箱子的体积大小 

typedef struct goods			//物品信息结构 
{
	int goods_num;				//物品号 
	int goods_volume;			//物品体积大小 
} ElementGoods;

typedef struct goods_node		//物品结点信息 
{
	int goods_num;				//物品号 
	int goods_volume; 			//物品体积 
	struct goods_node *next;
} GoodsLink;

typedef struct box_node			//箱子结点 
{
	int remember;				//箱子剩余体积 
	GoodsLink *goods_head;		//物品头结点 
	struct box_node *next;
} BoxLink;

void init_goods_info(ElementGoods data[])		//初始化物品信息 
{
	//自定义每个物品体积大小 
	int temp_vlume[GOODS_COUNT] = {3, 1, 5, 7, 18, 10, 12, 11, 14, 15};		
	for (int i = 0; i < GOODS_COUNT; ++i)		
	{
		data[i].goods_num = i+1;
		data[i].goods_volume = BOX_VOLUME;
		data[i].goods_volume = temp_vlume[i];
	}

	int exchange = 1;		//是否排过序标志 
	ElementGoods temp;
	for (int i = 0; i < GOODS_COUNT && exchange; ++i)			
	{
		exchange = 0;
		for (int j = 0; j < GOODS_COUNT - i - 1; ++j)
		{
			if(data[j].goods_volume < data[j + 1].goods_volume)
			{
				temp = data[j];
				data[j] = data[j + 1];
				data[j + 1] = temp;
				exchange = 1;			 					 	
			}
		}
	}
	
}


BoxLink *packing_box(ElementGoods data[])
{
	BoxLink *box_head = NULL, *box_tail = NULL, *p = NULL;
	GoodsLink *new_goods, *goods_tail = NULL, *q=NULL;
	
	for (int i = 0; i < GOODS_COUNT; ++i)
	{
		//从头开始找能够放下当前物品体积大小的箱子 
		p = box_head;
		while(p && (p->remember < data[i].goods_volume))	
			p = p->next;
	
		//是第一个箱子,或者找完了所有已经打开的箱子,放不下当前物品
		//需要打开一个新的箱子 
		if(!p)	 
		{
			p = (BoxLink *)malloc(sizeof(BoxLink));
			p->remember = BOX_VOLUME;					
			p->goods_head =NULL;
			p->next = NULL;				

			if(!box_head)
				box_head = box_tail = p;
			else
				box_tail = box_tail->next = p;
		}
	
		//生成新的物品
		//放进去物品之后,当前箱子体积为减去物品体积后的大小 
		p->remember -= data[i].goods_volume;		
		new_goods = (GoodsLink *)malloc(sizeof(GoodsLink));
		new_goods->goods_num = data[i].goods_num;
		new_goods->goods_volume = data[i].goods_volume;
		new_goods->next = NULL;
		
		//找物品尾结点 
		for(q=p->goods_head; q&&q->next; q=q->next)
			; 
		if(!q)
			p->goods_head = new_goods;
		else
			q->next = new_goods;
	}

	return box_head;
}


void output_box_info(BoxLink *box_head)
{
	BoxLink *ptr = box_head;
	GoodsLink *t = NULL;
	int i, cnt = 1;
	while(ptr)
	{
		printf("Box %d:\n", cnt++);
		printf("\tremember = %d \n", ptr->remember);
		printf("\tgoods : ");
		
		t = ptr->goods_head;
		i = 1;
		while(t)
		{
			printf("(%d goods num:%d, reamin volume:%d)  ",i++, t->goods_num, t->goods_volume);
			t = t->next;
		}
		printf("\n");
		ptr = ptr->next;
	}
}


int main(int argc, char const *argv[])
{
	ElementGoods goods_data[GOODS_COUNT] = { 0 };		
	BoxLink *box_head;							
	
	init_goods_info(goods_data);				
	box_head = packing_box(goods_data);			
	output_box_info(box_head);					

	return 0;
}
三维装箱问题是一个经典的组合优化问题,它的目标是将一系列给定的物体(每个物体有不同的体积)放入尽可能少的盒子中,且每个盒子的体积不能超过限制。 贪心算法是一种常用的解决方案之一,它每次选择能够容纳当前物体且剩余空间最小的盒子来放置物体。下面是一个使用贪心算法解决三维装箱问题的Python示例代码: ```python def pack_boxes(items, box_volume): items.sort(reverse=True) # 按照物体体积从大到小排序 boxes = [] for item in items: placed = False for box in boxes: if box['remaining_volume'] >= item: box['items'].append(item) box['remaining_volume'] -= item placed = True break if not placed: new_box = {'remaining_volume': box_volume - item, 'items': [item]} boxes.append(new_box) return boxes # 示例用法 items = [4, 5, 6, 7, 8, 9 # 物体的体积列表 box_volume = 10 # 盒子的体积限制 result = pack_boxes(items, box_volume) print(result) ``` 在上述代码中,我们首先对物体列表按照体积从大到小进行排序。然后,我们使用一个列表 `boxes` 来保存已经放置了物体的盒子,每个盒子的信息包括剩余的空间和已放置的物体列表。接着,我们遍历每个物体,对于每个物体,我们尝试将其放入已有的盒子中,如果找到一个能容纳该物体的盒子,则将其放入该盒子中,并更新盒子的剩余空间。如果找不到合适的盒子,则创建一个新的盒子,并将该物体放入其中。 最后,我们返回所有盒子的列表作为结果。在上述示例中,输出的结果是一个列表,每个元素表示一个盒子,包含该盒子里已放置的物体列表和剩余空间。 需要注意的是,贪心算法并不能保证一定得到最优解,但对于三维装箱问题来说,它通常能够给出较好的近似解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

春哥111

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

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

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

打赏作者

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

抵扣说明:

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

余额充值