贪心算法之木材装集装箱问题

原创 2013年12月06日 11:38:43

                                   贪心算法应用

                                             ——木材的装箱问题

一、问题描述:
给定一个集装箱,其长为L、宽为W、高为H。现有一批圆柱型木材,每根木材的长均为L,但是半径r不同。设第i根木材半径为ri。
问:如何装箱,使得集装箱的空间利用率最高?
 
 
 
 
二、算法设计:

——采用贪心算法思想,将箱子抽象为L*W*H的长方体,将木材抽象为底面半径为ri、长为L的圆柱体。

算法步骤:

  1、首先对圆柱体按半径大小从大到小进行排序

  2、取出圆柱体中底面半径最大的一个,从左下角坐标开始检查矩形空闲位置并判断当前圆柱体是否可以放入(判断圆柱体底面圆的圆心距是否合适,以及底面面积是否超过了空闲矩形的边框)。

  3、接下来再将剩余的圆柱体取出,重复步骤2直至矩形空间中不再能够容纳下剩余圆柱体中底

三、程序实现:

#include <iostream>
#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <math.h>
//#include <stdlib.h>
using namespace std;

#define MAXNUM 100
#define pi 3.141592653589

int columnum,count;
float H,W;


struct Circle_wood //圆柱形木头的数据结构
{
	double x,y,r;
	int sel;      //判断是否和别人相交
}cr[MAXNUM];

double dis(Circle_wood a,double x,double y) //两个圆圆心距
{
	return sqrt((a.x-x)*(a.x-x)+(a.y-y)*(a.y-y));
}

int sort(Circle_wood *wood,int n)//按圆柱半径由大到小排序  
{
	Circle_wood a;
	int j;
	for(int i=0;i<columnum;i++)
	{ 
		a=wood[i];
		j=i-1;
		while(j>=0 && wood[j].r<a.r)
		{
			wood[j+1]=wood[j];
			j=j-1;
		}
		wood[j+1]=a;
	}
	
	return 0;
}

int put(int now,double tx,double ty)//判断在位置(tx,ty)是否可以放下
{
	if(tx<cr[now].r || tx+cr[now].r>W || ty<cr[now].r || ty+cr[now].r>H)
		return 0; //不能放下,越界
	for(int i=0;i<now;i++)
		if(cr[i].sel)//判断是否和别人相交
			if(dis(cr[i],tx,ty)<(cr[i].r+cr[now].r-0.01)) //相交
				return 0;
	return 1;
}

void check(int now)//为第now个木头找位置
{ 
	double t,dx,dy;
	for(int i=0;i<now;i++)
	if(cr[i].sel)//对每个已插入的木头
	{
		t=cr[i].r+cr[now].r;
		for(int j=0;j<=360; j++)//对每个角度进行检查
		{ 
			dx=cr[i].x+t*cos(-pi/2.0 + j*pi/180.0);
			dy=cr[i].y+t*sin(-pi/2.0 + j*pi/180.0);
			if(put(now,dx,dy)==1)//找到合适位置了
			{ 
				count++;
				cr[now].x=dx;
				cr[now].y=dy;
				cr[now].sel=1;
				return ;
			}
		}
	}
}

void Gdy()//确定坐标并实现木材的定位
{
	count=0;int i;
	for(i=0;i<columnum;i++) //初始化
		cr[i].sel=0; 
	for(i=0;i<columnum;i++)
	{
		if(count==0 && cr[i].r <= H/2 &&cr[i].r <=W/2)//第一个能放进的
		{
			cr[i].x=cr[i].r;
			cr[i].y=cr[i].r;
			cr[i].sel=1;
			count++;
		}
		else
			check(i); //检查其他木头
	}
	
}


void draw()//画图
{
	int t=0;
	int k,j;
	char *S[MAXNUM]={"0 ","1 ","2 ","3 ","4 ","5 ","6 ","7 ","8 ","9 ","10","11","12","13","14","15","16","17","18","19","20",
	"21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45"};
	/*
	int *S[20];
	for(k=0,j=0;k<columnum;k++)
	{
		if(cr[k].sel==1)
        { 
		   *S[j]=(int)cr[k].r;
		   j++;
		}
	}
	*/
	HBRUSH hbrush_old;
	HDC    hdc     = GetWindowDC( GetDesktopWindow() );
	HPEN   hpen1   = CreatePen( PS_SOLID, 1, RGB(255,200,200) );// 创建浅色1像素宽度的实线画笔 
	HPEN   hpen2   = CreatePen( PS_DASH, 5, RGB(0,255,0) ); // 创建绿色5像素宽度的破折画笔
	HBRUSH hbrush1 = CreateSolidBrush( RGB(60,60,60) ); // 创建一个实体蓝色画刷 
	HBRUSH hbrush2 = CreateSolidBrush( RGB(255,255,255) ); //紫色 
	//HBRUSH hbrush3 = CreateSolidBrush( RGB(0,255,64) );//绿色
	//HBRUSH hbrush4 = CreateSolidBrush( RGB(128,255,0) );
	//HBRUSH hbrush5 = CreateSolidBrush( RGB(255,0,128) );//紫色

	HPEN   hpen_old= (HPEN)SelectObject( hdc, hpen1 );
	hbrush_old     = (HBRUSH)SelectObject( hdc, hbrush1);
	Rectangle(hdc,200,400,200+(int)(W*20),400-(int)(H*20)); 
	for(int i=0;i<columnum;i++)
	{
		if(i%4==0)
			hbrush_old = (HBRUSH)SelectObject( hdc, hbrush2);
		else if(i%4==1)
			hbrush_old = (HBRUSH)SelectObject( hdc, hbrush2);
		else if(i%4==2) 
			hbrush_old = (HBRUSH)SelectObject( hdc, hbrush2);
		else
			hbrush_old = (HBRUSH)SelectObject( hdc, hbrush2);
		if(cr[i].sel)
		{
			t=i;

			Ellipse( hdc,(int)(200+20*(cr[i].x-cr[i].r)), (int)(400-20*(cr[i].y+cr[i].r)), (int)(200+20*(cr[i].x+cr[i].r)), (int)(400-20*(cr[i].y-cr[i].r)) );//画圆
			TextOut( hdc,(int)(200+20*cr[i].x),(int)(400-20*cr[i].y),S[i+1],2); //i,signed i+1; 并用数字标记
			//TextOut( hdc,(int)(200+20*cr[i].x),(int)(400-20*cr[i].y),cr[i].r,2); //i,signed i+1; 并用数字标记
		}
		Sleep(750);
	}
	TextOut( hdc,(int)(200+20*cr[t].x),(int)(400-20*cr[t].y),S[t+1],2); //最后一个圆柱形木头放入
}


int main()//主函数
{
	FILE *fp;
	char filename[20];
	long start; //用以计算程序运行时间
	double area =0;
	int i;

	//printf(" 请输入数据文件:"); //读入圆柱形木头数据
	//scanf("%s",filename);
	
	if((fp=fopen("123.txt","r"))==NULL)
	{
		printf(" 输入文件不存在!\n ");//文件不存在则退出
		exit(0);
	}
	start=GetTickCount();
	//fscanf(fp,"%d",&columnum);
	cout<<"请输入圆柱个数:";
	cin>>columnum;
	cout<<"集装箱的宽:";
	cin>>W;
	cout<<"集装箱的高:";
	cin>>H;
	//cout<<"集装箱的长:";
	//cin>>L;
	for(i=0;i<columnum;i++) 
		fscanf(fp,"%lf",&cr[i].r); 
	sort(cr,columnum); //先进行对木头的排序
	Gdy(); //这个是本程序的主体函数
	for(i=0;i<columnum;i++) //计算一个木头所占有的面积
		if(cr[i].sel) 
			area += pi*cr[i].r*cr[i].r; 
	draw(); //画出图形
	//printf(" %ld\n",columnum);
	//printf("%lf\n%lf\n%lf\n",W,H);
	for(i=0;i<columnum && cr[i].sel==1;i++)
	{
        cout<<"可装入的圆柱序号为"<<i<<endl;
	}
	printf(" 装入货物的面积为:%lf\n",area);
	printf(" 集装箱利用率为:%lf%%\n",area/(W*H)*100);//计算集装箱利用率
	printf(" 程序运行时间为:%f秒\n ",(GetTickCount()-start)/1000.0); //计算程序运行时间
	getchar();
	getchar();
	return 0;
}


四、程序结果:

 

五、算法效率

考虑的最坏情况,每个圆定位都要遍历之前n-1个圆,角度要经过360次计算,要经过n-1次计算与其他圆是否相交,故最差为O(n^3),最好是O(n^2)

贪心算法的运用 ——集装箱的装箱问题

贪心算法的运用 ——集装箱的装箱问题 一、问题描述: 给定一个集装箱,其长为L,宽为W和高为H,现有一批圆柱形木材,每根木材的长均为L,但是半径不同,设第i根木材半径为ri。问如何装箱,使得集装...
  • lgfeng218
  • lgfeng218
  • 2011年09月24日 15:02
  • 3264

19:装箱问题(4.6算法之贪心)

19:装箱问题总时间限制: 1000ms 内存限制: 65536kB 描述 一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3...
  • qq_26919935
  • qq_26919935
  • 2017年09月10日 20:26
  • 87

贪心,最优装载问题

问题描述: 有一批集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为Wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。 分析: 可用贪心算法求解,采用重量最轻...
  • cumt_wangxiang
  • cumt_wangxiang
  • 2016年06月14日 15:18
  • 248

关于贪心算法...

描述:贪心算法:选择当前状况下(局部状况)的最优解,从而的出全局状况的最优解。(得出来的全局解是否为最优需证明)需证明啊!!!证明!!! 例: 图标排列 时间限制(普通/Java):10...
  • Triose
  • Triose
  • 2015年01月23日 21:41
  • 306

算法java实现--贪心算法--最优装载问题

最优装载问题算法的java实现(贪心算法) 具体问题描述以及C/C++实现参见网址...
  • qipanliming
  • qipanliming
  • 2014年04月29日 11:14
  • 4443

【算法导论】贪心算法之活动安排问题

对于许多最优化问题来说,采用动态规划来求解最优解有点大材小用了,只需要采用更简单有效的贪心算法就行了。贪心算法就是所做的每一步选择都是当前最佳的,通过局部最佳来寻求全局最佳解。就像砝码称重一样,总是优...
  • tengweitw
  • tengweitw
  • 2013年11月27日 22:18
  • 2265

2018搜狐编程题-贪心算法-二维装箱问题

参考原文请点击打开链接 题目描述 一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6。这...
  • u010240385
  • u010240385
  • 2017年08月28日 22:09
  • 391

NYOJ - 14 - 会场安排问题(区间相关问题---选择不相交区间-贪心算法)

描述 学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办。小刘的工作就是安排学校小礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想...
  • qq_34594236
  • qq_34594236
  • 2016年10月19日 17:10
  • 260

【算法题】切割木材

切割木材
  • xiaxzhou
  • xiaxzhou
  • 2017年05月21日 16:59
  • 516

贪心算法之最大不相交区间数问题

贪心算法之最大不相交区间数问题 数轴上有n个区间[ai,bi],要求选择尽量多个区间,使得这些区间两两没有公共点。 贪心策略: 按照b1 证明: 我们对a1,a2……...
  • u012736084
  • u012736084
  • 2014年02月23日 15:25
  • 2056
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:贪心算法之木材装集装箱问题
举报原因:
原因补充:

(最多只允许输入30个字)