装箱问题的算法研究

山东大学 赵一帆

问题描述

在箱子装载问题中,有若干个容量为c的箱子和n个待装载入箱子中的物品。物品i需占s[i]个单元(0<s[i]≤c)。所谓成功装载(feasible packing),是指能把所有物品都装入箱子而不溢出,而最优装载(optimal packing)则是指使用了最少箱子的成功装载。

问题分析

这道题目是算法课设发给我要求完成的题目,给了四种基本的算法,再加上avl树和竞赛树优化(竞赛树那部分我写的还是有点满意),后续我感觉可以用模拟退火来做一下,所以就搜集资料尝试了一下,之后百度百科说遗传算法也可以做,所以就自己想象凭空捏造了一波遗传算法,欢迎指出不足点。
其实这两种思路都是有更有目标和优化的搜索而已。

模拟退火思路

每次交换50个rand()对,如果替换结果就保留这个交换,否则不保留,不停在函数上面溜达,其实我也不知道这个函数长什么样子。

遗传算法思路

之前没有搞过这个算法,先学的,感觉很多二手博客非常不尊重达尔文同志的思想,强行忽略了遗传中很多的步骤,也有可能是他们生物没有学的很好,所以我加上了染色体交叉互换的环节,一共有n*(n/32)个染色体,每个染色体上面有32个基因,每个基因表示i和j是否进行交换,1表示为显性,0表示为隐形,这样空间最多可以表达<1000的数量,可惜最后进化效果并不是很好,大概进化的时间还是太短了,或者说这道题本身可能就不是很适合进化,因为箱子的交换有可能会走向好的方向,但是保留之后并不能显然的确定会向更好的方向进行移动。

性能分析

可以发现我写的退火算法和遗传算法确实不咋地,有时间再改进改进把,但是实际上我感觉真的挺难优化的。

大物品情况:
答案:

运行时间:




中等物品情况下:
答案:

运行时间:




小物品:
答案:

运行时间:



代码分析

void FF()
{LL startTime = clock();int hasNumber = 0;for(int i = 1;i <= n;++i)    {bool flag = false;for(int j = 1;j <= hasNumber&&!flag;++j){if(c_has[j] >= s[i]) {c_has[j] -= s[i];flag = true;}}if(!flag) c_has[++hasNumber] = c - s[i];  }cout<<"最先匹配法耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}
int FFCT(int mode)   //竞赛树做法
{LL startTime = clock(),hasNumber = 0;for(int i = 1;i <= 2*n;++i) cmt[i] = c;for(int i = 1;i <= n;++i){int x = 1;while(x < n) {if(cmt[x * 2] >= s[i]) x = x * 2;else x = x * 2 + 1;}cmt[x] -= s[i];while(x > 1) {x = x/2;cmt[x] = max(cmt[x*2],cmt[x*2 + 1]);}}for(int i = n;i <= 2 * n - 1;++i) if(cmt[i] != c) hasNumber++;if(mode == 0){cout<<"最先匹配(竞赛树优化)法耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl; }return hasNumber;
}

void FFD()
{LL startTime = clock();int hasNumber = 0;for(int i = 1;i <= n;++i) s_max[i] = s[i];sort(s_max+1,s_max+n+1,cmp);for(int i = 1;i <= n;++i)   {bool flag = false;for(int j = 1;j <= hasNumber&&!flag;++j){if(c_has[j] >= s_max[i]) {c_has[j] -= s_max[i];flag = true;}}if(!flag) c_has[++hasNumber] = c - s_max[i];  }cout<<"最先匹配递减法耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}

void FFDCT()    //竞赛树做法
{LL startTime = clock(),hasNumber = 0;for(int i = 1;i <= n;++i) s_max[i] = s[i];sort(s_max+1,s_max+n+1,cmp);for(int i = 1;i <= 2*n;++i) cmt[i] = c;for(int i = 1;i <= n;++i){int x = 1;while(x < n) {if(cmt[x * 2] >= s_max[i]) x = x * 2;else x = x * 2 + 1;}cmt[x] -= s_max[i];while(x > 1) {x = x/2;cmt[x] = max(cmt[x*2],cmt[x*2 + 1]);}}for(int i = n;i <= 2 * n - 1;++i) if(cmt[i] != c) hasNumber++;cout<<"最先匹配递减法(竞赛树优化)耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}
void BF()    //搜索获得大于其的最小值
{LL startTime = clock();int hasNumber = 0;c_has[0] = 599999999;for(int i = 1;i <= n;++i)  {int boxMark = 0;for(int j = 1;j <= hasNumber;++j)if(c_has[j] >= s[i] && c_has[j] < c_has[boxMark]) boxMark = j;if(boxMark == 0)  c_has[++hasNumber] = c - s[i];else   c_has[boxMark] -= s[i]; }cout<<"最优匹配法耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}
void BFBetter()  //使用平衡树获得大于其的最小值
{LL startTime = clock();int hasNumber = 0;for(int i = 1;i <= n;++i)    {double findNum = find_down(rt,s[i]);if(findNum < 1e8) {del(rt,findNum);    //删除和插入耗时太多,所以当箱子空间小的时候 Insert(rt,findNum-s[i]); //这个算法的复杂度反而会高 }else {hasNumber ++;Insert(rt,c-s[i]);}}cout<<"最优匹配法(结合平衡树)耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}

void BFD()  //搜索获得大于其的最小值
{LL startTime = clock();int hasNumber = 0;c_has[0] = 599999999;for(int i = 1;i <= n;++i) s_max[i] = s[i];sort(s_max+1,s_max+n+1,cmp);for(int i = 1;i <= n;++i) {int boxMark = 0;for(int j = 1;j <= hasNumber;++j)if(c_has[j] >= s_max[i] && c_has[j] < c_has[boxMark]) boxMark = j;if(boxMark == 0)  c_has[++hasNumber] = c - s_max[i];else   c_has[boxMark] -= s_max[i]; }cout<<"最优匹配法递减耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}

void BFDBetter()    //使用平衡树获得大于其的最小值
{LL startTime = clock();int hasNumber = 0;for(int i = 1;i <= n;++i) s_max[i] = s[i];sort(s_max+1,s_max+n+1,cmp);for(int i = 1;i <= n;++i)   {double findNum = find_down(rt,s_max[i]);if(findNum < 1e8) {del(rt,findNum);    //删除和插入耗时太多,所以当箱子空间小的时候 Insert(rt,findNum-s_max[i]); //这个算法的复杂度反而会高 }else {hasNumber ++;Insert(rt,c-s_max[i]);}}cout<<"最优匹配递减法(结合平衡树)耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<hasNumber<<"个"<<endl;
}
void Simulated()
{LL startTime = clock(),hasNumber = 0;for(int i = 1;i <= n;++i) s_max[i] = s[i];//sort(s+1,s+n+1,cmp);int best = FFCT(1);int ans = best;for(AT = 300;AT > eps;AT *= D) {for(int i = 1;i <= n;++i) s_min[i] = s[i];for(int i = 1;i <= 5;++i) swap(s[rand()%n+1],s[rand()%n+1]);int now = FFCT(1);best = min(best,now);if(now < ans || exp((ans - now)/AT*600) > (double)rand()/RAND_MAX)  ans = now;else{for(int i = 1;i <= n;++i) s[i] = s_min[i];}}cout<<"模拟退火+最先匹配递减法(竞赛树优化)耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<best<<"个"<<endl; for(int i = 1;i <= n;++i) s[i] = s_max[i];
}
//很多变量开的是unsinged int,请注意const int maxn = 1001;
using namespace std;
int T,n;double s[maxn],si[maxn],c;
uint animal[46][maxn][36][2];double Value[maxn],cmt[maxn*2];
void bir()
{for(int i = 1;i <= 30;i+=2){int son = 30+(i+1)/2,t = (i+1)%2;for(int j = 1;j <= n; ++j)     for(int k = 1;k <= (n/32)+1;++k)    //对于每一个染色体{int pos = rand() % 2;animal[son][j][k][t] = animal[i][j][k][pos];if(rand() % 2 == 0) //染色体交叉 for(int lapTimes = 1;lapTimes <= 9;++lapTimes){int lapPos = rand() % 32 + 1;int old = (animal[son][j][k][t]>>(lapPos - 1)) % 2;int other = (animal[i][j][k][pos^1]>>(lapPos - 1)) % 2;if(old != other) animal[son][j][k][t] = ((((animal[son][j][k][t]>>lapPos)<<1)+ other )<<(lapPos - 1))+animal[son][j][k][t] % (1<<(lapPos - 1));}//染色体变异for(int varTimes = 1;varTimes <= 4;++varTimes){int varPos = rand() % 32 + 1;animal[son][j][k][t] = ((((animal[son][j][k][t]>>varPos)<<1)+ rand()%2 )<<(varPos - 1))+animal[son][j][k][t] % (1<<(varPos - 1));}   } }
}
void clum(int x)
{for(int i = 1;i <= n; ++i) si[i] = s[i];for(int j = 1;j <= n; ++j)  for(int k = 1;k <= (n/32)+1;++k){int need = animal[x][j][k][0]|animal[x][j][k][1];//显性和隐形基因 int times = 0,pos = (k-1)*32+times;if(j >= pos||pos > n) continue;   //该部分基因无意义,不表达,减少训练次数 while(++times <= 32){if(need % 2 == 1) swap(si[j],si[pos]);need >>= 1;}}Value[x] = FFCT();//cout<<Value[x]<<endl;
}
int rank[55],sel[55];
void select()
{for(int i = 1;i <= 45;++i)if(Value[i] == 0) clum(i); //进行计算 memset(sel,0,sizeof(sel));for(int i = 1;i <= 45;++i) //获得从小到大排名{rank[i] = 0;for(int j = 1;j <= 45;++j){if(sel[j]) continue;if(rank[i] == 0) rank[i] = j;if(Value[j] < Value[rank[i]]) rank[i] = j;}}//30次交换for(int i = 1;i <= 45;++i){int find = 0;for(int j = 1;j <= 45&&find == 0; ++j){if(rank[j] == i) find = j;}swap(Value[i],Value[find]);for(int j = 1;j <= n; ++j)   for(int k = 1;k <= (n/32)+1;++k){swap(animal[i][j][k][0],animal[find][j][k][0]);swap(animal[i][j][k][1],animal[find][j][k][1]);}} for(int i = 31; i <= 45;++i) Value[i] = 0;
}
void solve()
{cin>>c>>n;for(int i = 1;i <= n; ++i) scanf("%lf",&s[i]);int startTime = clock();for(int i = 1;i <= 30;++i) for(int j = 1;j <= n;++j)for(int k = 1;k <= (n/32)+1;++k)for(int p = 0;p < 2;++p)animal[i][j][k][p] = ((uint)rand()<<17) +((uint)rand()<<2) + (rand() % 4);for(int tims = 1;tims <= 500 ;++tims){bir(); //获得子代 select(); //人为选择 }cout<<"遗传算法法耗时"<<clock()-startTime<<"毫秒,";cout<<"消耗箱子"<<Value[1]<<"个"<<endl;
}

关于装箱问题的算法研究相关推荐

  1. python:关于三维装箱问题的算法研究-3

    基于 三维装箱问题的算法研究-2 的基础,对整个过程进行了优化 因为后面研究的视图依赖于Three.js进行成像,需要写一些简单的vue页面,所以把整个算法包括数据格式的调用做成了django后端系统 ...

  2. python:关于三维装箱问题的算法研究-2

    基于 三维装箱问题的算法研究-1 的基础上,对整个装箱过程发生的函数进行封装 # -*- coding: utf-8 -*- from matplotlib import pyplot as plt ...

  3. python:关于三维装箱问题的算法研究-1

    先准备一个用来图显的函数 # -*- coding: utf-8 -*- from matplotlib import pyplot as plt #设置图表刻度等格式 from matplotlib ...

  4. 经典算法研究系列:二、Dijkstra 算法初探

    经典算法研究系列:二.Dijkstra 算法初探  July   二零一一年一月 ====================== 本文主要参考:算法导论 第二版.维基百科. 写的不好之处,还望见谅. 本 ...

  5. 基于图机器学习的微生物网络关系预测算法研究

    龙亚辉预答辩公告 浏览次数:410日期:2021-03-19编辑:院研究生秘书 预答辩公告 论文题目 基于图机器学习的微生物网络关系预测算法研究 答辩人 龙亚辉 指导教师 骆嘉伟 答辩委员会 主席 王 ...

  6. 多倍体单体型组装算法研究

    多倍体单体型组装算法研究 喻昕   [摘要]:人类已知的疾病都与基因有着直接或者间接的联系,研究不同个体间基因序列的差异对于了解人类的遗传,以及预防疾病等方面都有着重要的作用.SNP是单核苷酸多态性, ...

  7. 基于癌症基因组学数据的miRNA 功能模块识别算法研究

    题目: 基于癌症基因组学数据的miRNA 功能模块识别算法研究 摘要: 大量研究表明miRNA 的异常表达与癌症的发生.发展有关,且miRNA 通常以组合的 方式发挥其协同调控作用.因此,研究miRN ...

  8. 近期活动盘点:心电数据标注系统和深度学习诊断算法研究、2019年第六届清华大学大数据社会科学讲习班...

    想知道近期有什么最新活动?大数点为你整理的近期活动信息在此: 第四期医工结合研讨会:心电数据标注系统和深度学习诊断算法研究 2019年7月11日 7月11日,"医工结合系列研讨会第四期会议: ...

  9. 《基于压缩传感的匹配追踪重建算法研究》读书笔记

    基于压缩传感的匹配追踪重建算法研究 1.压缩感知与传统数据获取和处理过程比较: 压缩感知理论表明,在对信号获取的同时,就对数据进行适当的压缩. 传统的数据获取和处理过程主要包括:采样.压缩.传输.解压 ...

最新文章

  1. LINQ学习之旅——第二站LTQ之标准数据库操作(增查删改)
  2. 关于高并发,我想告诉你这些!
  3. 守护线程与非守护线程
  4. 把txt文件中的json字符串写到plist文件中
  5. MySQL+Tomcat+JVM,看完还怕面试官
  6. Golang笔记——channel(管道)
  7. 扩展卡尔曼滤波器设计
  8. 苹果ppt_苹果发布会PPT,为何总能惊艳到你
  9. 圣经 创世纪 1:20-22
  10. 时间单位的换算(秒,毫秒,微秒,纳秒,皮秒)
  11. 【Python】pandas的read_csv参数简略概括(header,path),DataFrame的返回值describe,plot,head
  12. Speed Test隐私政策
  13. UILabel根据字数计算高度,宽度,行数
  14. win python_winpython_winpython linux_python win - 云+社区 - 腾讯云
  15. Python 打造微信群聊天机器人(带操作界面)
  16. sdk+windows安装教程
  17. 读书感想20221218
  18. python打开zip文件_Python ZIP 文件创建与读取
  19. html中如何引用其外部字体,css引入外部字体
  20. 破解基础----背的滚瓜烂熟差不多就会破解

热门文章

  1. 静态工厂方法和实例工厂方法的区别
  2. Matplotlib之3D图像
  3. CTF萌新入坑指南(web篇)(21.6.5已更新)
  4. 微信小程序使用地图map (详细)
  5. 信息安全——Java实现凯撒加密算法和解密算法----详细的代码注释
  6. ubuntu 9.04 安装手记
  7. 网站降权剖析、恢复思路
  8. Linux中的黑洞(black hole)-/dev/null
  9. 猫猫向前冲 Week8作业B题
  10. Linux DISPLAY 设置