算法:矿点间行走-Use最小堆+带权最短路径
最小堆
function MinHeap:Ctor(tData) self.tArray = tData or {} if #self.tArray > 1 then self:adjust() end end function MinHeap:GetSize() return #self.tArray end -- 调整 function MinHeap:adjust() local nLastParentIndex = math.floor((#self.tArray - 2) / 2 + 1) for nParentIndex = nLastParentIndex, 1, -1 do self:siftdown(nParentIndex) end end -- 下沉 function MinHeap:siftdown(nParentIndex) local nChildLeftIndex = nParentIndex * 2 if not self.tArray[nChildLeftIndex] then -- 没有左子节点 return end local nChildLeftValue = self.tArray[nChildLeftIndex] if self.tArray[nChildLeftIndex].nValue then nChildLeftValue = self.tArray[nChildLeftIndex].nValue end local nChildRightIndex = nParentIndex * 2 + 1 local nChildRightValue = self.tArray[nChildRightIndex] if self.tArray[nChildRightIndex] and self.tArray[nChildRightIndex].nValue then nChildRightValue = self.tArray[nChildRightIndex].nValue end local nParentValue = self.tArray[nParentIndex] if self.tArray[nParentIndex].nValue then nParentValue = self.tArray[nParentIndex].nValue end local nChildIndex if nChildLeftValue then nChildIndex = nChildLeftIndex end if nChildRightValue and nChildRightValue < nChildLeftValue then nChildIndex = nChildRightIndex end local nChildValue = self.tArray[nChildIndex] if self.tArray[nChildIndex].nValue then nChildValue = self.tArray[nChildIndex].nValue end if nChildValue < nParentValue then local parent = self.tArray[nParentIndex] self.tArray[nParentIndex] = self.tArray[nChildIndex] self.tArray[nChildIndex] = parent self:siftdown(nChildIndex) end end -- 上浮 function MinHeap:siftup(nChildIndex) if nChildIndex == 1 then -- 根节点 return end local nChildValue = self.tArray[nChildIndex] if self.tArray[nChildIndex].nValue then nChildValue = self.tArray[nChildIndex].nValue end local nParentIndex = math.floor(nChildIndex / 2) local nParentValue = self.tArray[nParentIndex] if self.tArray[nParentIndex].nValue then nParentValue = self.tArray[nParentIndex].nValue end if nChildValue < nParentValue then local parent = self.tArray[nParentIndex] self.tArray[nParentIndex] = self.tArray[nChildIndex] self.tArray[nChildIndex] = parent self:siftup(nParentIndex) end end -- 插入 function MinHeap:Insert(value) table.insert(self.tArray, value) self:siftup(#self.tArray) end -- 获取根节点 function MinHeap:GetMin() if self:GetSize() < 1 then return nil end local rootValue = self.tArray[1] self.tArray[1] = self.tArray[#self.tArray] self:siftdown(1) self.tArray[#self.tArray] = nil return rootValue end return MinHeap
带权最短路径
function Graph:Ctor(tLinks) self.tLinks = tLinks or {} end -- 最短路径算法Dijkstra function Graph:GetShortestPaths(nSrc, nDest, tBanDest) -- lua_trace("nSrc %d, nDest %d", nSrc, nDest) if nSrc == nDest then return {} end tBanDest = tBanDest or {} if tBanDest[nDest] then return {} end local tDefaultValue = {} table.insert(tDefaultValue, {nIndex = nSrc, nValue = 0}) -- 起点到其他点的邻接表 -- self.tAdjacencyList[nSrc] = {} local tAdjacencyList = {} local oMinHeap = MinHeap:new(tDefaultValue) local bConnectDest = false -- 循环遍历直到找到到达目标的最小值 while(true) do local bSmallerNode = false local minValue = oMinHeap:GetMin() local nIndex = minValue.nIndex local nValue = minValue.nValue -- 起点到这个点的权值 local tLink = self.tLinks[nIndex] if not tLink then lua_trace("nIndex %d", nIndex) lua_trace("tLink"..tLink) end -- 遍历邻接点,计算起点到他们的权值 for nNeighborIndex, nEdgeValue in pairs(tLink) do local nNewValue = nValue + nEdgeValue -- if not self.tAdjacencyList[nSrc][nNeighborIndex] or self.tAdjacencyList[nSrc][nNeighborIndex].nValue > nNewValue then if nNeighborIndex ~= nSrc and not tBanDest[nNeighborIndex] and (not tAdjacencyList[nNeighborIndex] or tAdjacencyList[nNeighborIndex].nValue > nNewValue) then -- 更新起点到该点的前置节点和权值 local tNewValue = {nIndex = nNeighborIndex, nPreIndex = nIndex, nValue = nNewValue} tAdjacencyList[nNeighborIndex] = tNewValue oMinHeap:Insert(tNewValue) bSmallerNode = true if nNeighborIndex == nDest then bConnectDest = true end end end -- 已经没有更短的路径 if oMinHeap:GetSize() == 0 or (bConnectDest and not bSmallerNode) then break end end -- 没有找到路径 if not bConnectDest then return nil end -- 回溯最短路径 --{nSrc, ..., ..., nDest} local tShortestPaths = {} -- local tShortestPaths_Reverse = {} local nCurIndex = nDest table.insert(tShortestPaths, 1, nCurIndex) -- table.insert(tShortestPaths_Reverse, nCurIndex) while(true) do nCurIndex = tAdjacencyList[nCurIndex].nPreIndex if nCurIndex == nSrc then table.insert(tShortestPaths, 1, nSrc) -- table.insert(tShortestPaths_Reverse, nSrc) break end local tValue = tAdjacencyList[nCurIndex] table.insert(tShortestPaths, 1, tValue.nIndex) -- table.insert(tShortestPaths_Reverse, tValue.nIndex) end return tAdjacencyList[nDest].nValue, tShortestPaths end function Graph:GetAllShortestPaths(tBanDest) local tAllShortestPaths = {} for nSrc, _ in pairs(self.tLinks) do tAllShortestPaths[nSrc] = tAllShortestPaths[nSrc] or {} for nDest, _ in pairs(self.tLinks) do if nSrc ~= nDest and not tAllShortestPaths[nSrc][nDest] then tAllShortestPaths[nDest] = tAllShortestPaths[nDest] or {} local nValue, tShortestPaths = self:GetShortestPaths(nSrc, nDest, tBanDest) tAllShortestPaths[nSrc][nDest] = {tPath = tShortestPaths, nValue = nValue} end end end return tAllShortestPaths end