python 使用 最大生成樹 解決 營救問題
題目描述
你是紅軍指揮官,在一場軍事演習中,你的部分軍隊被藍軍包圍了。藍軍包圍的方式如下
在上圖中,每個頂點表示藍軍的部隊,頂點中數字表示藍軍在此處的人數(千人),兩點間的邊表示藍軍兩個部隊間形成的火線,火線構成的圈即是一道包圍,一條火線的戰鬥力為其相連兩個部隊的人數和,也是你要進攻這條火線所要消耗的兵力。你可以同時進攻藍軍的多條火線,請以成本最低的方式打破藍軍包圍,營救被包圍的部隊,計算出所需要消耗的兵力數(千人)
輸入
- 輸入包含多個測試例。第一行是一個整數n,表示測試測試例數量。
- 對每個測試例:
第一行是一個正整數m(2<m≤200),是藍軍部隊數。
每個藍軍部隊有兩行:
一行3個正整數:i為部隊編號(0≤i≤m-1),ai為藍軍部隊人數(千人)(1≤ai≤100),bi為與該部隊能形成火線的部隊數量(1≤bi≤m-1)。
一行有bi個正整數,分別是與部隊i形成火線的部隊編號,數字間有空格。 - 至少有一個包圍。
輸出
每個測試例輸出一行,是一個正整數:打破包圍營救戰友的最小消耗兵力。
輸入樣例
1
3
0 1 2
1 2
1 2 2
0 2
2 3 2
0 1
輸出結果
3
解題思路
程式碼實現
使用並查集優化的Kruskal演算法實現
#!/usr/bin/env python3
#rescue.py
#fumiama 20201115
from heapq import heappop, heappush
class UnionFindSet(object):
def __init__(self, nodes):
self.fatherMap = {}
self.setNumMap = {}
for node in nodes:
self.fatherMap[node] = node
self.setNumMap[node] = 1
def findFather(self, node):
father = self.fatherMap[node]
if (node != father):
father = self.findFather(father)
self.fatherMap[node] = father
return father
def isSameSet(self, a, b):
return self.findFather(a) == self.findFather(b)
def union(self, a, b):
if a is None or b is None: return
aFather = self.findFather(a)
bFather = self.findFather(b)
if (aFather != bFather):
aNum = self.setNumMap[aFather]
bNum = self.setNumMap[bFather]
if (aNum <= bNum):
self.fatherMap[aFather] = bFather
self.setNumMap[bFather] = aNum + bNum
self.setNumMap.pop(aFather)
else:
self.fatherMap[bFather] = aFather
self.setNumMap[aFather] = aNum + bNum
self.setNumMap.pop(bFather)
class Node(object):
def __init__(self, name, size, links):
self.name = name
self.size = size
self.links = links
def __repr__(self):
return "(節點:" + str(self.name) + ", 大小:" + str(self.size) + ", 連線到:" + str(self.links) + ")"
class Graph(object):
def __init__(self):
self.edges = []
self.nodes = set()
self.sizes = dict(map=int)
self._edgesSets = [] #識別重複邊
def addNode(self, node):
self.nodes.add(node)
self.sizes[node.name] = node.size
def calcEdgeWeights(self):
for node in self.nodes:
for link in node.links:
edge = (-(node.size + self.sizes[link]), node.name, link) #邊權為負構造大頂堆
sedge = {node.size + self.sizes[link], node.name, link}
if sedge not in self._edgesSets:
heappush(self.edges, edge)
self._edgesSets.append(sedge)
def rescue(self):
forest = UnionFindSet(self.sizes.keys())
edges = self.edges.copy()
cost = 0
while edges:
edge = heappop(edges)
if forest.isSameSet(edge[1], edge[2]): cost -= edge[0]
else: forest.union(edge[1], edge[2])
return cost
def __repr__(self):
return "圖資訊:\n邊: " + str(self.edges) + "\n點: " + str(self.nodes)
if __name__ == '__main__':
n = int(input())
graph = Graph()
while n:
m = int(input())
while m:
no, size, edgeCnt = map(int, input().split())
links = [int(x) for x in input().split()]
graph.addNode(Node(no, size, links))
m -= 1
graph.calcEdgeWeights()
#print(graph)
minCost = graph.rescue()
#print("最小兵力:", minCost)
print(minCost)
n -= 1
相關文章
- python 生成csv亂碼問題解決方法Python
- 解決 Python 指令碼無法生成結果的問題Python指令碼
- 一類生成樹計數問題。
- Trace檔案過量生成問題解決
- 回溯法(排列樹)解決八(N)皇后問題
- 解決「問題」,不要解決問題
- macOSX中使用python matplotlib模組的問題解決MacPython
- Oracle Trace檔案過量生成問題解決Oracle
- 圖論 最小生成樹問題(最優連線問題)圖論
- 解決python MySQLdb import Error問題PythonMySqlImportError
- python待解決問題筆記Python筆記
- [Leetcode]827.使用回溯+標記解決最大人工島問題LeetCode
- 貨車運輸(LCA+最大生成樹)
- pyinstaller 生成 exe 的閃退問題解決方案
- 如何解決機器學習樹整合模型的解釋性問題機器學習模型
- 徹底解決Python編碼問題Python
- python 中文亂碼問題解決方案Python
- 解決無法使用VI的問題
- Homestead 使用問題及解決方式
- 解決使用Git Bash亂碼問題Git
- CKEditor使用中遇到的問題解決
- 解決在使用Amoeba遇到的問題
- 解決問題
- 做運營,如何解決問題
- 最大子陣列和問題的解陣列
- 一個簡單的統計問題(解決方案:Trie樹)
- 使用動態規劃完美解決硬幣找零問題(Python)動態規劃Python
- 發現問題,解決問題
- Python 解決 :NameError: name 'reload' is not defined 問題PythonError
- 解決python中文編碼錯誤問題Python
- 決策樹模型(3)決策樹的生成與剪枝模型
- 前端必會演算法 - 最小生成樹問題前端演算法
- 【演算法學習筆記】生成樹問題探究演算法筆記
- 動態生成html元素繫結事件iphone失效問題解決HTML事件iPhone
- 前端生成海報圖技術選型與問題解決前端
- DIV+CSS相容解決DIV最大寬度和最小寬度問題CSS
- Oledb操作Excel時欄位最大值255的問題解決方案Excel
- Mysql使用kill命令解決死鎖問題MySql