好的伙计们......我对这一个感到有点难过..
我在合并的位置有一个项目表。这些项目分布在不同的行(如仓库)之间。我已经计算了发送到哪里以及起始位置和结束位置之间的距离。
现在,我需要开发一个以最短移动开始的报告,然后从其FINISH位置找到下一个最短移动,其中START位置最接近第一个移动FINISH位置...所以如果我从仓库移动obj A第20行到第30行,我希望我的下一行是下一个最接近的行,可能在第30行,这也是最短的距离。
item | start_loc | end_loc | distance
A | 5 | 10 | 5
B | 14 | 11 | 3
C | 20 | 1 | 19
D | 10 | 13 | 3
E | 10 | 5 | 5
F | 10 | 6 | 4
因此上面的表格将被订购
D,B,F,A,E,C
基本上我想优化旅行量,花最少的时间空手而归..
使用ColdFusion和SQL执行此操作..
根据以下评论进行修改: 我将尝试进一步澄清..上面的表格将被订购D,B,F,A,E,C因为: D的距离最短 - 3; B是下一个关闭D的结束(13-> 14); F因为移动B在11处结束,10是具有移动的下一个最近的行,并且F在该行中具有最短的移动距离; bc F以6结束,A从5开始; E bc A以10结束,E从10开始; C因为它是最不方便的(最长的,没有任何结束)所以它是最后的
更新 我调整了下面选择的答案来处理我的表格等等。但是,它正在跳过其中一行,我不确定为什么?
<!-- Add some columns to the working table for calculations -->
<cfquery name="updateWorking" datasource="planning" dbtype="obdc">
ALTER TABLE working
ADD move_distance FLOAT;
ALTER TABLE working
ADD start_loc FLOAT;
ALTER TABLE working
ADD finish_loc FLOAT;
ALTER TABLE working
ADD move_order INT;
</cfquery>
<cfquery name="updateWorking2" datasource="planning" dbtype="obdc">
UPDATE working
SET start_loc = LEFT(Storage_Bin, 5)
WHERE marked_consolidate_loc IS NOT NULL;
UPDATE working
SET finish_loc = LEFT(marked_consolidate_loc, 5)
WHERE marked_consolidate_loc IS NOT NULL;
UPDATE working
SET move_distance = finish_loc - start_loc
WHERE marked_consolidate_loc IS NOT NULL;
UPDATE working
SET move_distance = ABS(move_distance)
where move_distance < 0
</cfquery>
<!-- Query to show all the moves in order by distance, shortest first -->
<cfquery name="report" datasource="planning" dbtype="obdc">
SELECT id, Material, marked_consolidate, marked_consolidate_loc, marked_consolidate_su,
max_pallet, mixed_skid, Storage_Bin, Storage_Unit, move_distance, finish_loc, start_loc
FROM working
WHERE marked_consolidate IS NOT NULL
AND mixed_skid = 0
ORDER BY move_distance ASC
</cfquery>
<!-- What is the shortest move? Do it first -->
<cfquery name="firstMove" datasource="planning" dbtype="obdc" maxRows="1">
Select id, Material, marked_consolidate, marked_consolidate_loc, marked_consolidate_su,
max_pallet, mixed_skid, Storage_Bin, Storage_Unit, move_distance, finish_loc, start_loc
FROM working
WHERE marked_consolidate IS NOT NULL
AND mixed_skid = 0
ORDER BY move_distance ASC, start_loc ASC
</cfquery>
<!--- set the Move Number --->
<cfset moveNumber = 1>
<!-- List to remember ID of moves that have been completed -->
<cfset tripSequence = ''>
<!-- Update the first selection as the first move -->
<cfquery name= "updateMove" datasource="planning" dbtype="obdc">
UPDATE working
SET move_order = #moveNumber#
WHERE id = #firstMove.id#;
</cfquery>
<cfset moveNumber = moveNumber + 1>
<cfset tripSequence = ListAppend(tripSequence, "#firstMove.id#")>
<cfset lastMoveFinish = #firstMove.finish_loc#>
<!--- number of trips remaining --->
<cfset numberOfTrips = (report.recordCount) - 1>
<!-- Loop through the whole table -->
<cfloop from="1" to="#numberOfTrips#" index="i">
<!--- determine next move to compare to --->
<cfloop query="report">
<!--- Has it been moved already?--->
<cfif listContains(tripSequence, #report.id#)>
<!-- If so, continue to next row -->
<cfcontinue>
</cfif>
<!-- If not, remember this one -->
<cfset nextLocationID = report.id>
<cfset nextLocationFinishLoc = report.finish_loc>
<cfset nextLocationDist = abs(lastMoveFinish - report.start_loc)>
</cfloop>
<!--- compare this move with other moves, if the next one is shorter remember it --->
<cfloop query="report">
<!--- Has it been moved already? --->
<cfif listContains(tripSequence, #report.id#)>
<cfcontinue>
</cfif>
<!-- How far is this move from your current location? -->
<cfset nextLocationDistance = abs(lastMoveFinish - report.start_loc)>
<!-- If this move is closer to you than the one you selected above, remember it instead -->
<cfif nextLocationDistance LT nextLocationDist>
<cfset nextLocationID = report.id>
<cfset nextLocationFinishLoc = report.finish_loc>
<cfset nextLocationDist = abs(lastMoveFinish - report.start_loc)>
</cfif>
</cfloop>
<!-- once you have the closest move, remember it and update the column -->
<cfset tripSequence = ListAppend(tripSequence, nextLocationID)>
<!-- Update the move column -->
<cfquery name= "updateMove" datasource="planning" dbtype="obdc">
UPDATE working
SET move_order = #moveNumber#
WHERE id = #nextLocationID#;
</cfquery>
<!-- Increment the Move Number -->
<cfset moveNumber = moveNumber + 1>
<!--- set the ending of your last move --->
<cfset lastMoveFinish = nextLocationFinishLoc>
</cfloop>
<!-- BELOW IS OUTPUT OF THE REPORT -->
<body>
<!-- Build the report -->
<table border='1'>
<tr>
<th colspan="7">
<h2>Consolidation Report</h2>
</th>
</tr>
<tr>
<td>Move Order</td>
<td>Current Loc</td>
<td>Current SU</td>
<td>Item Number</td>
<td>Qty To Move</td>
<td>Moved To Loc</td>
<td>Moved To SU</td>
</tr>
<!-- Query to show all the moves in order by distance, shortest first -->
<cfquery name="showReport" datasource="planning" dbtype="obdc">
SELECT Material, marked_consolidate, marked_consolidate_loc, marked_consolidate_su,
Storage_Bin, Storage_Unit, move_order
FROM working
WHERE marked_consolidate IS NOT NULL
AND mixed_skid = 0
ORDER BY move_order
</cfquery>
<cfloop query="showReport">
<tr>
<cfoutput>
<td>#showReport.move_order#</td>
<td>#showReport.Storage_Bin#</td>
<td>#showReport.Storage_Unit#</td>
<td>#showReport.Material#</td>
<td>#showReport.marked_consolidate#</td>
<td>#showReport.marked_consolidate_loc#</td>
<td>#showReport.marked_consolidate_su#</td>
</cfoutput>
</tr>
</cfloop>
</table>
<cfoutput>#tripSequence#</cfoutput>
<body>
输出是一个包含49行的表..但其中一行Move Number为空,它跳过Move Number:48。想法?
所有行在逻辑上都是正确的,它只是跳过48并且没有将Null行放在它应该的位置(逻辑上将在移动30周围)。
答案 0 :(得分:1)
解决TSP问题,是吗?这是我的解决方案,除非你运行数千个节点,否则性能应该很好。
<cfset data = queryNew(
"item,start_loc,end_loc,distance",
"VARCHAR,INTEGER,INTEGER,INTEGER",
[
[ "A", 5, 10, 5 ],
[ "B", 14, 11, 3 ],
[ "C", 20, 1, 19 ],
[ "D", 10, 13, 3 ],
[ "E", 10, 5, 5 ],
[ "F", 10, 6, 4 ]
]
)>
<cfset tripSequence = []>
<!--- BEGIN: determine first item --->
<cfquery name="closestLocation" dbType="query" maxRows="1">
SELECT
*
FROM
[data]
ORDER BY
[distance] ASC,
[start_loc] ASC
</cfquery>
<!--- add item --->
<cfset tripSequence.add(closestLocation.item)>
<!--- END: determine first item --->
<!--- number of trips remaining --->
<cfset numberOfTrips = (data.recordCount - 1)>
<cfloop from="1" to="#numberOfTrips#" index="i">
<!--- BEGIN: determine next trip to compare to --->
<cfloop query="data">
<!--- must not have been done already --->
<cfif arrayFind(tripSequence, data.item)>
<cfcontinue>
</cfif>
<cfset nextLocation = {
item: data.item,
end_loc: data.end_loc,
distance: abs(closestLocation.end_loc - data.start_loc)
}>
</cfloop>
<!--- END: determine next trip to compare to --->
<!--- BEGIN: compare with remaining trips --->
<cfloop query="data">
<!--- must not have been done already --->
<cfif arrayFind(tripSequence, data.item)>
<cfcontinue>
</cfif>
<cfset nextLocationDistance = abs(closestLocation.end_loc - data.start_loc)>
<cfif nextLocationDistance lt nextLocation.distance>
<cfset nextLocation = {
item: data.item,
end_loc: data.end_loc,
distance: nextLocationDistance
}>
</cfif>
</cfloop>
<!--- END: compare with remaining trips --->
<!--- add item --->
<cfset tripSequence.add(nextLocation.item)>
<!--- take item as base for the next iteration --->
<cfset closestLocation = nextLocation>
</cfloop>
<cfoutput>#arrayToList(tripSequence, ", ")#</cfoutput>
答案 1 :(得分:0)
有趣的问题,sql和逻辑谜题。显然是一个递归的工作,用一个while循环来保持简单:
select CONCAT(a.item, ',', b.item, ',', c.item, ',', d.item, ',', e.item, ',', f.item) as route,
sum(abs(a.end_loc - b.start_Loc) + abs(b.end_loc - c.start_Loc) + abs(c.end_loc - d.start_Loc) + ABS(d.end_loc - e.start_Loc) + abs(e.end_loc - f.start_Loc)) as distance
from
#examplework a
join #examplework b on b.item != a.item
join #examplework c on c.item != a.item and c.item != b.item
join #examplework d on d.item != a.item and d.item != b.item and d.item != c.item
join #examplework e on e.item != a.item and e.item != b.item and e.item != c.item and e.item != d.item
join #examplework f on f.item != a.item and f.item != b.item and f.item != c.item and f.item != d.item and f.item != e.item
group by CONCAT(a.item, ',', b.item, ',', c.item, ',', d.item, ',', e.item, ',', f.item)
order by distance
因此推销员悖论再次在sql中得到解决(darn college homework)。为了逐步执行它,我设置了步骤变量,然后抓取未出现在工作表中的最近项目。一旦所有项目都在工作表中,while循环就会关闭。希望有所帮助。
如果这是TSP,编辑呐喊,你不能简单地选择一个节点并希望最近的导致最佳路线。你需要暴力破坏它,看看所有可能的组合并挑选一个需要最少旅行的组合。这是一个例子:
add_filter('login_redirect', function ($redirect_to, $request, $user){
if (user_can($user, 'registered')){
return bp_core_get_user_domain( $user->ID );
}
}
这实际上是解决TSP的唯一方法,另一种方法将为您提供一条好路线,蛮力方法将为您提供最佳路线。