最优切割问题.docx
《最优切割问题.docx》由会员分享,可在线阅读,更多相关《最优切割问题.docx(16页珍藏版)》请在冰豆网上搜索。
![最优切割问题.docx](https://file1.bdocx.com/fileroot1/2022-12/12/b1a403eb-4ed7-433e-ba17-14cfe20bbfa9/b1a403eb-4ed7-433e-ba17-14cfe20bbfa91.gif)
最优切割问题
最短路的实际应用
————最优切割问题
99131059魏炜
一:
问题的提出
某些工业部门(如贵重石才的加工等)采用截断切割的加工方式。
这里“截断切割”是指将物体沿某个切割平面分成两个部分。
从一个长方体中加工出一个已知尺寸位置预定的长方体(这个长方体的对应表面是平行的),通常要经过6次截断切割。
设水平切割单位面积的费用是垂直切割单位面积的r倍,且当先后两次垂直切割的平面(不管它们之间是否穿插水平切割)不平行时,因调整刀具需额外费用e。
试为这些部门设计一种安排个面加工次序的方法。
待加工的长方体和成品的长,宽,高分别为10,14.5,19和3,2,4两者左侧面,正面,底面之间的距离分别为6,7,9(单位均为厘米)垂直切割的费用为每平方厘米1元。
r和e数据如下(a)r=1,e=0(b)r=1.5e=2
二:
问题的分析
刚拿到这个题目时,还是很茫然的,不知应该用什么样的方法进行解答,当学到图与网络分析的时候,突然觉得这道题是不是可以用最短路的来求解呢?
抱着试试看的心里,我将问题成功的转换成了求一个图的最短路的问题,而我们要求最短路就是要先求出每一条边所表示的权重。
三:
问题的解决
设待加工体的长、宽、高分别为a0、b0、c0。
六个切割面分别位于左、右、前后、上下相应为S1、S2、S3、S4、S5、S6。
这六个面与成品的相应外测面的距离分别为d1、d2、d3、d4、d5、d6。
不失一般性设d1>=d2、d3>=d4、d5>=d6。
故可以只考虑S1在S2前、S3在S4前、S5在S6前被切割的方式。
I:
e=0r=1的情形。
先考虑如何建立图形。
将切割问题转化为求图的最短路径问题。
赋权网络图G*的建立。
由于共计切6刀,因此我们想到要建立一个三维网络图:
①图形的解释。
图中各个点表示每个切割状态。
例如
表示最初状态,
表示已经切割完毕。
表示左前被切一刀,前后各被切一刀,上下没有被切。
②求权*的过程。
G的边(
表示石材被切割的一个过程。
若两个定点之间有弧,当且仅当
的时候,则我们把相应的弧上的权看成是切割过程的费用。
。
当我们得到这个计算方法时,看到图形有27个点,需要计算很多权。
因为我们要用图中Dijkstra算法*。
这个看似很繁琐,但当我们做了每两点之间的权后,发现是有规律可循的,其规律如下:
总有两个参量是不变的,因此我们总能得到关于一个参量的结果。
如果
没有变化,且满足
,因此剩余变量差总为1,后面为不变量两者相应的长、宽、高中的两者相乘即可,所以得
到底是怎么样得一个状态呢?
其实也是有规律可以遵循的,例如:
,
首先第一和第三变量不变,因此权为
而相应数均为2,因此均已完成切割,所以
。
同理可以计算出权,这些均为算法的进行奠定了基础。
我们知道待加工长方体长、宽、高分别为10、14.5、19,成品为3、2、4。
因此两者各侧面的距离如下:
(即
6
1
7
5.5
6
9
算法已经成型,因此在这里我们在PASCAL平台上进行编程实现便可以得到我们想要的最优切割的排列路径为:
其权为374,程序见附录。
II:
e=2r=1.5的情形。
从上面的分析可以看出,若还用上一个网络赋权图,显然达不到要求,因为有些边上的权是要增加的,而某些边的权即可不变。
显然我们应该寻找一个新的图来进行求解。
由于问题的要求,不管中间是否穿插平行切割,只要先后两次垂直切割不平行时,就要加入转刀费,即额外费用e。
而这两个垂直平面切割方式只能有三种可能情况:
①先切一对平行面,再切另外一对,费用增加e;
②先切一个面,再切一对平行面,再切另外一个面,费用增加2e;
③每切一次的面总是两两互相垂直,费用增加3e。
这样的话我们可以得到一下结论:
切割情况
必经点
(1,0,z)(2,0,z)(2,1,z)
(0,1,z)(0,2,z)(1,2,z)
(0,1,z)(1,1,z)(2,1,z)
(1,0,z)(1,1,z)(1,2,z)
(1,0,z)(1,1,z)(2,1,z)
(0,1,z)(1,1,z)(1,2,z)
若我们去掉{(2,1,z)︱z=0,1,2}和{(1,2,z)︱z=0,1,2}点集和与之关联的边得到新的赋权网络图如下:
赋权网络图2赋权网络图3
现在我们的问题非常明了细化,就是要从
找到一条最短路径。
从两者之间取小,就可以得到最优化切割方案:
(源程序见附录)
1:
其权为443.5。
2:
其权为468.5。
从而我们得到问题的解答。
关键词解释:
I:
若图G的每一条边e都对应一个实数
,则称
为改边的权,并称图为赋权图。
II:
设
是赋权图G中从U到V的路径,则称
=
为路径P的权。
III:
在赋权图G中,从顶点U到顶点V具有最小权的路
称为从U到V的最短路。
附录:
一:
全体的切割情况解决方案源代码。
programcut(input,output);const
r=1;
max=9999;{定义一个默认的最大数}
type
mat=array[1..27,1..27]ofreal;
disttype=array[1..27]ofreal;
zuo_biao=record
x,y,z:
integer;
end;
vset=array[1..27]ofzuo_biao;
pathtype=setof1..27;{把路径定义为一个集合}
var
a0,b0,c0,u1,u2,u3,u4,u5,u6,ai,bi,ci,m,wm:
real;
da_cost:
mat;{相连矩阵}
dist:
disttype;{从开始顶点到其余各点的最短路径}
i,j,k,l,p,n:
integer;
path:
array[1..27]ofpathtype;{记录所切割的路径}
s:
setof1..27;
v:
vset;{定义的各个顶点}
begin
writeln('pleaseinputdatawhichhavebeenknowed:
a0,b0,c0,u1,u2..u6');
read(a0,b0,c0,u1,u2,u3,u4,u5,u6);{输入一些已知量}
i:
=1;{自动生成整张图的各个顶点的三维坐标,共有27个顶点}
forl:
=0to2do
forp:
=0to2do
forn:
=0to2do
withv[i]do
beginv[i].x:
=n;
v[i].y:
=p;
v[i].z:
=l;
i:
=i+1
end;
fori:
=1to27do{以下为求解相连顶点的权值}
begin
forj:
=1to27do
begin
if(v[i].x+v[i].y+v[i].z+1=v[j].x+v[j].y+v[j].z)and(v[i].x<=v[j].x)and(v[i].y<=v[j].y)and(v[i].z<=v[j].z)and(ithenbegin
ifv[i].x=0thenai:
=a0;
ifv[i].x=1thenifu1>u2thenai:
=a0-u1elseai:
=a0-u2;
ifv[i].x=2thenai:
=a0-u1-u2;
ifv[i].y=0thenbi:
=b0;
ifv[i].y=1thenifu3>u4thenbi:
=b0-u3elsebi:
=b0-u4;
ifv[i].y=2thenbi:
=b0-u3-u4;
ifv[i].z=0thenci:
=c0;
ifv[i].z=1thenifu5>u6thenci:
=c0-u5elseci:
=c0-u6;
ifv[i].z=2thenci:
=c0-u5-u6;
m:
=(v[j].x-v[i].x)*(bi*ci)+(v[j].y-v[i].y)*(ai*ci)+(v[j].z-v[i].z)*(ai*bi)*r;
da_cost[i,j]:
=m
end
elseda_cost[i,j]:
=max{如果没有直接路径的话则把其设置为默认的最大值}
end
end;
{以下我们所采用的是Diskstra的算法来求解图中的最短路径}
fori:
=1to27do
begin
dist[i]:
=da_cost[1,i];
ifdist[i]=[1]+[i]
elsepath[i]:
=[]
end;
s:
=[1];{先找出开始顶点}
fork:
=1to26do
begin
wm:
=max;
j:
=1;
fori:
=1to27do
ifnot(iins)and(dist[i]beginj:
=i;
wm:
=dist[i]
end;
s:
=s+[j];
fori:
=1to27do{如果有通过其他顶点而改变权值的话则加以修改}
ifnot(iins)and(dist[j]+da_cost[j,i]thenbegin
dist[i]:
=dist[j]+da_cost[j,i];
path[i]:
=path[j]+[i]{把此顶点加入路径集合}
end
end;
writeln('theshortestdistancebetween1to27is');
writeln(dist[27]);{输出权值}
writeln('theshortestpathbetween1to27is');
fori:
=1to27do
ifiinpath[27]{输出路径}
thenbeginwrite(i);write('-----')
end
end.
调试测试的结果为:
pleaseinputdatawhichhavebeenknowed:
a0,b0,c0,u1,u2..u6
1014.5196175.569
theshortestdistancebetween1to27is
3.7400000000E+02
theshortestpathbetween1to27is
1-----10-----13-----14-----23-----26-----27
二:
去掉部分点集及与其相关连的边后的解决方案源代码。
1:
去掉{(2,1,z)︱z=0,1,2}:
programhalfcut1(input,output);
const
r=1.5;{此处r变为1.5}
max=9999;
e=2;
type
mat=array[1..27,1..27]ofreal;
disttype=array[1..27]ofreal;
zuo_biao=record
x,y,z:
integer;
end;
vset=array[1..27]ofzuo_biao;
pathtype=setof1..27;
var
a0,b0,c0,u1,u2,u3,u4,u5,u6,ai,bi,ci,m,wm:
real;
da_cost:
mat;
dist:
disttype;
i,j,k,x,y,l,p,n:
integer;
path:
array[1..27]ofpathtype;
s:
setof1..27;
v:
vset;
begin
writeln('pleaseinputdatawhichhavebeenknowed:
a0,b0,c0,u1,u2..u6');
read(a0,b0,c0,u1,u2,u3,u4,u5,u6);
i:
=1;
forl:
=0to2do
forp:
=0to2do
forn:
=0to2do
withv[i]do
beginv[i].x:
=n;
v[i].y:
=p;
v[i].z:
=l;
i:
=i+1
end;
fori:
=1to27do
begin
forj:
=1to27do
begin
if(v[i].x+v[i].y+v[i].z+1=v[j].x+v[j].y+v[j].z)and(v[i].x<=v[j].x)and(v[i].y<=v[j].y)and(v[i].z<=v[j].z)and(ithenbegin
ifv[i].x=0thenai:
=a0;
ifv[i].x=1thenifu1>u2thenai:
=a0-u1elseai:
=a0-u2;
ifv[i].x=2thenai:
=a0-u1-u2;
ifv[i].y=0thenbi:
=b0;
ifv[i].y=1thenifu3>u4thenbi:
=b0-u3elsebi:
=b0-u4;
ifv[i].y=2thenbi:
=b0-u3-u4;
ifv[i].z=0thenci:
=c0;
ifv[i].z=1thenifu5>u6thenci:
=c0-u5elseci:
=c0-u6;
ifv[i].z=2thenci:
=c0-u5-u6;
m:
=(v[j].x-v[i].x)*(bi*ci)+(v[j].y-v[i].y)*(ai*ci)+(v[j].z-v[i].z)*(ai*bi)*r;
da_cost[i,j]:
=m
end
elseda_cost[i,j]:
=max
end
end;
{以下是重新加权的边}
da_cost[4,5]:
=da_cost[4,5]+e;
da_cost[5,8]:
=da_cost[5,8]+e;
da_cost[8,9]:
=da_cost[8,9]+e;
da_cost[13,14]:
=da_cost[13,14]+e;
da_cost[14,17]:
=da_cost[14,17]+e;
da_cost[17,18]:
=da_cost[17,18]+e;
da_cost[22,23]:
=da_cost[22,23]+e;
da_cost[23,26]:
=da_cost[23,26]+e;
da_cost[26,27]:
=da_cost[26,27]+e;
{以下代码主要是解决去掉相关点及其与之关联的边后其相连矩阵需采取的动作}
fori:
=1to27do
if(i=6)or(i=15)or(i=24){根据顶点坐标对应的点来处理}
thenbegin
forj:
=1to27do
da_cost[i,j]:
=max{把其值设置为最大值的话就相当于无边关联}
end;
fory:
=1to27do
if(y=6)or(y=15)or(y=24)
thenbegin
forx:
=1to27do
da_cost[x,y]:
=max
end;
fori:
=1to27do
begin
dist[i]:
=da_cost[1,i];
ifdist[i]=[1]+[i]
elsepath[i]:
=[]
end;
s:
=[1];
fork:
=1to26do
begin
wm:
=max;
j:
=1;
fori:
=1to27do
ifnot(iins)and(dist[i]beginj:
=i;
wm:
=dist[i]
end;
s:
=s+[j];
fori:
=1to27do
ifnot(iins)and(dist[j]+da_cost[j,i]thenbegin
dist[i]:
=dist[j]+da_cost[j,i];
path[i]:
=path[j]+[i]
end
end;
writeln('theshortestdistancebetween1to27is');
writeln(dist[27]);
writeln('theshortestpathbetween1to27is');
fori:
=1to27do
ifiinpath[27]
thenbeginwrite(i);write('-----')
end
end.
调试测试的结果为:
pleaseinputdatawhichhavebeenknowed:
a0,b0,c0,u1,u2..u6
1014.5196175.569
theshortestdistancebetween1to27is
4.4350000000E+02
theshortestpathbetween1to27is
1-----4-----13-----14-----17-----26-----27
2:
同理我们可以得到去掉{(1,2,z)︳z=0,1,2}的源代码:
programhalfcut2(input,output);
const
r=1.5;
max=9999;
e=2;
type
mat=array[1..27,1..27]ofreal;
disttype=array[1..27]ofreal;
zuo_biao=record
x,y,z:
integer;
end;
vset=array[1..27]ofzuo_biao;
pathtype=setof1..27;
var
a0,b0,c0,u1,u2,u3,u4,u5,u6,ai,bi,ci,m,wm:
real;
da_cost:
mat;
dist:
disttype;
i,j,k,x,y,l,p,n:
integer;
path:
array[1..27]ofpathtype;
s:
setof1..27;
v:
vset;
begin
writeln('pleaseinputdatawhichhavebeenknowed:
a0,b0,c0,u1,u2..u6');
read(a0,b0,c0,u1,u2,u3,u4,u5,u6);
i:
=1;
forl:
=0to2do
forp:
=0to2do
forn:
=0to2do
withv[i]do
beginv[i].x:
=n;
v[i].y:
=p;
v[i].z:
=l;
i:
=i+1
end;
fori:
=1to27do
begin
forj:
=1to27do
begin
if(v[i].x+v[i].y+v[i].z+1=v[j].x+v[j].y+v[j].z)and(v[i].x<=v[j].x)and(v[i].y<=v[j].y)and(v[i].z<=v[j].z)and(ithenbegin
ifv[i].x=0thenai:
=a0;
ifv[i].x=1thenifu1>u2thenai:
=a0-u1elseai:
=a0-u2;
ifv[i].x=2thenai:
=a0-u1-u2;
ifv[i].y=0thenbi:
=b0;
ifv[i].y=1thenifu3>u4thenbi:
=b0-u3elsebi:
=b0-u4;
ifv[i].y=2thenbi:
=b0-u3-u4;
ifv[i].z=0thenci:
=c0;
ifv[i].z=1thenifu5>u6thenci:
=c0-u5elseci:
=c0-u6;
ifv[i].z=2thenci:
=c0-u5-u6;
m:
=(v[j].x-v[i].x)*(bi*ci)+(v[j].y-v[i].y)*(ai*ci)+(v[j].z-v[i].z)*(ai*bi)*r;
da_cost[i,j]:
=m
end
elseda_cost[i,j]:
=max
end
end;
da_cost[2,5]:
=da_cost[2,5]+e;
da_cost[5,6]:
=da_cost[5,6]+e;
da_cost[6,9]:
=da_cost[6,9]+e;
da_cost[11,14]:
=da_cost[11,14]+e;
da_cost[14,15]:
=da_cost[14,15]+e;
da_cost[15,18]:
=da_cost[15,18]+e;
da_cost[20,23]:
=da_cost[20,23]+e;
da_cost[23,24]:
=da_cost[23,24]+e;
da_cost[24,27]:
=da_cost[24,27]+e;
fori:
=1to27do
if(i=8)or(i=17)or(i=26){根据去掉顶点的坐标来确定的点}
thenbegin
forj:
=1to27do
da_cost[i,j]:
=max
end;
fory:
=1to27do
if(y=8)or(y=17)or(y=26)
thenbegin
forx:
=1to27do
da_cost[x,y]:
=max
end;
fori:
=1to27do
begin
dist[i]:
=da_cost[1,i];
ifdist[i]=[1]+[i]
elsepath[i]:
=[]
end;
s:
=[1];
fork:
=1to26do
begin
wm:
=max;
j:
=1;
fori:
=1to27do
ifnot(iins)and(dist[i]beginj:
=i;
wm:
=dist[i]
end;
s:
=s+[j];
fori:
=1to27do
ifnot(iins)and(dist[j]+da_cost[j,i]thenbegin
dist[i]:
=dist[j]+da_cost[j,i];
path[i]:
=path[j]+[i]
end
end;
writeln('theshortestdistancebetween