分析
三维装箱问题是NPC问题,可以考虑用启发式算法求解,但无法得到最优解
数据清洗
对每个物品判断能否被装
保证每个物品翻转成长>=宽>=高
- 能否被袋装
同时满足两个条件:
对最大号袋子而言 - 袋子长+袋子高≥物品长+物品高;
- 袋子宽+袋子高≥物品宽+物品高
- 能否被箱装
对最大号箱子而言
同时满足三个条件 - 箱子长>=物品长
- 箱子宽>=物品宽
- 箱子高>=物品高
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fer(i,a,b) for(int i=a;i<b;i++)
const int N1=1e4+5,N2=1e4,N3=5200;
struct good{//物品
int casenum;
int l,w,h;//长宽高
int num;//数量
bool fpack,fbox;//是否可袋装,是否可盒装
bool f[9];
};
struct order{
int casenum;//订单编号
vector<good> goods;//物品
};
struct package{
int l,w,h;
};
//order orders[N3];
good goods[N1];
package packages[9]={{250,190,1},{300,250,1},{400,330,1},{450,420,1},
{165,120,55},{200,140,70},{200,150,150},{270,200,90},{300,200,170}};
signed main(){
FILE *fp;
if((fp=fopen("sourceData.csv","r"))==0){
cout<<"error while opening the file"<<endl;exit(0);
}
cout<<"test1"<<endl;
//bool tmpf=1;
fer(i,0,N2){
int a,b,c,d,e;
fscanf(fp,"%d,%d,%d,%d,%d\n",&a,&b,&c,&d,&e);
goods[i].casenum=a;
goods[i].l=b;
goods[i].w=c;
goods[i].h=d;
goods[i].num=e;
// if(b>=c&&c>=d)tmpf=1;
// else tmpf=0;
//
}
//cout<<tmpf;
cout<<"test2"<<endl;
int fpackcnt=0,fboxcnt=0;
fer(i,0,N2){//判断每个物品能否袋装
if(goods[i].l+goods[i].h<=packages[3].l+packages[3].h
&&goods[i].w+goods[i].h<=packages[3].w+packages[3].h){
goods[i].fpack=1;goods[i].f[3]=1;
fpackcnt++;
}else goods[i].fpack=0;
}
fer(i,0,N2){//判断每个物品能否箱装
if(goods[i].l<=packages[8].l&&goods[i].w<=packages[8].w
&&goods[i].h<=packages[8].h){
goods[i].fbox=1;goods[i].f[8]=1;
fboxcnt++;
}else goods[i].fbox=0;
}
fer(i,0,9){
if(i==3||i==8)continue;
if(i<=2){//0,1,2,3是袋
fer(j,0,N2){
if(goods[j].l+goods[j].h<=packages[i].l+packages[i].h
&&goods[j].w+goods[j].h<=packages[i].w+packages[i].h){
goods[j].f[i]=1;
}else goods[j].f[i]=0;
}
}else{
fer(j,0,N2){
if(goods[j].l<=packages[i].l&&goods[i].w<=packages[i].w
&&goods[j].h<=packages[i].h){
goods[j].f[i]=1;
}else goods[j].f[i]=0;
}
}
}
cout<<"test3"<<endl;
fp=fopen("dataCleanFor1.csv","w");
fer(i,0,N2){
fprintf(fp,"%d,%d,%d,%d,%d,%d,%d",goods[i].casenum,goods[i].l,
goods[i].w,goods[i].h,goods[i].num,goods[i].fpack,goods[i].fbox);
fer(j,0,9){
fprintf(fp,",%d",goods[i].f[j]);
}
fprintf(fp,"\n");
}
fclose(fp);
cout<<fpackcnt<<endl;
cout<<fboxcnt<<endl;
return 0;
}
/*
9456
7926
*/
将清洗可视化
可视化代码
import numpy as np # 用来处理数据
import matplotlib.pyplot as plt
import csv
exampleFile = open("dataCleanFor1.csv") # 打开csv文件
exampleReader = csv.reader(exampleFile) # 读取csv文件
exampleData = list(exampleReader) # csv数据转换为列表
length_zu = len(exampleData) # 得到数据行数
length_yuan = len(exampleData[0]) # 得到每行长度
# print(length_zu)
# print(length_yuan)
x = list()
y = list()
z = list()
fpack=list()
fbox=list()
for i in range(0, length_zu):
x.append((int)(exampleData[i][1]))
y.append((int)(exampleData[i][2]))
z.append((int)(exampleData[i][3]))
fpack.append((int)(exampleData[i][5]))
fbox.append((int)(exampleData[i][6]))
xc=list()
yc=list()
zc=list()
for i in range(0,length_zu):
if fpack[i]==0:
xc.append(x[i])
yc.append(y[i])
zc.append(z[i])
fig = plt.figure(figsize=(12, 6), facecolor='w')
plt.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.9)
ax = fig.add_subplot(131,projection = '3d') # 创建一个三维的绘图工程
ax.set_title('The Source Data') # 设置本图名称
ax.set_xlabel('Length') # 设置x坐标轴
ax.set_ylabel('Width') # 设置y坐标轴
ax.set_zlabel('Height') # 设置z坐标轴
ax.scatter(x, y, z, c = 'b') # 绘制数据点 c: 'r'红色,'y'黄色,等颜色
plt.grid(True)
ax2 = fig.add_subplot(132,projection = '3d') # 创建一个三维的绘图工程
ax2.set_title('Clean of packages') # 设置本图名称
ax2.set_xlabel('Length') # 设置x坐标轴
ax2.set_ylabel('Width') # 设置y坐标轴
ax2.set_zlabel('Height') # 设置z坐标轴
ax2.scatter(x, y, z, c = 'b',label="Can be bagged") # 绘制数据点 c: 'r'红色,'y'黄色,等颜色
ax2.scatter(xc,yc,zc,c='r',label="Can't be bagged")
plt.grid(True)
xc=list()
yc=list()
zc=list()
for i in range(0,length_zu):
if fbox[i]==0:
xc.append(x[i])
yc.append(y[i])
zc.append(z[i])
ax3 = fig.add_subplot(133,projection = '3d') # 创建一个三维的绘图工程
ax3.set_title('Clean of boxes') # 设置本图名称
ax3.set_xlabel('Length') # 设置x坐标轴
ax3.set_ylabel('Width') # 设置y坐标轴
ax3.set_zlabel('Height') # 设置z坐标轴
ax3.scatter(x, y, z, c = 'b',label="Can be boxed") # 绘制数据点 c: 'r'红色,'y'黄色,等颜色
ax3.scatter(xc,yc,zc,c='r',label="Can't be boxed")
plt.grid(True)
plt.show()
exampleFile.close()
装箱
参考三维装箱问题的组合启发式算法
不同之处在于,本题数据达到1e4,且有9种耗材,其中4种是柔性的袋子
下面给出了一个比较粗糙的转5号箱的算法代码
fer(i,0,9){//计算各耗材体积
packages[i].v=packages[i].h*packages[i].l*packages[i].w;
}
fer(i,0,N3){//初始化订单
orders[i].casenum=i;
fer(j,0,9)orders[i].packnum[j]=0;
}
//只箱装的情况
fer(i,0,N2){//物品对应订单
int casen=goods[i].casenum;
if(goods[i].fpack)orders[i].goods.pb(goods[i]);
}
fer(i,0,N3){//处理每个订单
orders[i].goodsize=orders[i].goods.size();
sort(orders[i].goods.begin(),orders[i].goods.end(),goodscmp);//物品由大到小排序
//set<package> pk;
set<point> st;
int lz=0,lx=0;
st.insert((point){0,0,0});
fer(j,0,orders[i].goodsize){
fer(k,0,orders[i].goods[j].num){
bool flag=0;
set<point>::iterator it=st.begin();
int maxl=packages[8].l,maxw=packages[8].w,maxh=packages[8].h;
for(it;it!=st.end();it++){//遍历每一个可放置点判断是否可放置
if(orders[i].goods[j].l+(*it).x<=maxl&&orders[i].goods[j].w+(*it).y<=maxw
&&orders[i].goods[j].h+(*it).z<=maxh){//找到,放置
flag=1;
st.insert((point){orders[i].goods[j].l+(*it).x,(*it).y,(*it).z});
st.insert((point){(*it).x,orders[i].goods[j].w+(*it).y,(*it).z});
st.insert((point){(*it).x,(*it).y,orders[i].goods[j].h+(*it).z});
st.erase(*it);
break;
}
}
if(!flag){//没找到,开一个新箱子
st.clear();
st.insert((point){0,0,0});
orders[i].packnum[8]++;
}
}
}
}
fp=fopen("ans1.csv","w");
fer(i,0,N2){
fprintf(fp,"%d,%d,%d,%d,%d,%d,%d",goods[i].casenum,goods[i].l,
goods[i].w,goods[i].h,goods[i].num,goods[i].fpack,goods[i].fbox);
fer(j,0,9){
fprintf(fp,",%d",goods[i].f[j]);
}
fprintf(fp,",%d",orders[goods[i].casenum].packnum[8]);
fprintf(fp,"\n");
}
fclose(fp);