装箱问题的算法研究

山东大学 赵一帆

问题描述

在箱子装载问题中,有若干个容量为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. 2015年各银行无抵押信用贷款利率及额度是多少?
  2. R中方差,协方差,相关系数
  3. 快速复制数据库表中的数据SQL
  4. windows下buildbot 的搭建及config文件讲解
  5. php 鼠标点击图片放大,鼠标移入放大图片预览效果实现
  6. 笔记:python设计模式
  7. 在linux centos 7上安装maven
  8. 细谈最近上线的Vue2.0项目(一)
  9. 编译安装postfix+sasl+mysql+dovecot+extmail构建完成的邮件系统(一)
  10. C 什么是句柄?为什么会有句柄?HANDLE
  11. gensim提取一个句子的关键词_包含关键字 关键词提取 的文章 - 科学空间|Scientific Spaces...
  12. VS2015安装包-下载
  13. 使用 Sprinkles 构建您自己的类型安全版本的 Tailwind CSS
  14. 2021莆田六中一高考成绩查询入口,2021,我们来了 ——莆田六中2021届《青春•励志•圆梦》高三高考动员誓师大会...
  15. 【洛谷习题】皇后游戏
  16. Linux退出man命令手册,Linux中如何退出man命令
  17. 【BZOJ】【P1135】【POI2009】【Lyz】【题解】【线段树+Hall定理】
  18. 新茶饮式资本扩张,该停脚歇歇了
  19. ADOBE AIR是什么?
  20. ROI Pooing

热门文章

  1. 当你讨厌一个人的时候,那个人也会讨厌你
  2. ToB,慢生意下易被忽略的5个认知
  3. 单点登陆和无状态登陆
  4. element-plus 表格单元格的合并
  5. 雷达极化分解、极化目标分解相关
  6. 解决】无法连接 MKS:套接字连接尝试次数太多正在放弃
  7. 在此像各位推荐一本书《好妈妈胜过好老师》。
  8. 微信小程序输入框键盘显示时,上推固定在底部的按钮
  9. 塔子月赛第一场——一坤题坐牢场
  10. 如何下载 Google Chrome 离线安装包