![](/img/trans.png)
[英]Dividing a graph to triple-vertices graphs such the sum of weights of edges is minimized
[英]Dividing a graph in three parts such the maximum of the sum of weights of the three parts is minimized
我想將具有N個加權頂點和N-1個邊的圖分成三個部分,使得每個部分中所有頂點的權重之和的最大值最小化。 這是我想解決的實際問題, http://www.iarcs.org.in/inoi/contests/jan2006/Advanced-1.php
我考慮了以下方法
/*Edges are stored in an array E, and also in an adjacency matrix for depth first search.
Every edge in E has two attributes a and b which are the nodes of the edge*/
min-max = infinity
for i -> 0 to length(E):
for j -> i+1 to length(E):
/*Call depth first search on the nodes of both the edges E[i] and E[j]
the depth first search returns the sum of weights of the vertices it visits,
we keep track of the maximum weight returned by dfs*/
Adjacency-matrix[E[i].a][E[i].b] = 0;
Adjacency-matrix[E[j].a][E[j].b] = 0;
max = 0
temp = dfs(E[i].a)
if temp > max then max = temp
temp = dfs(E[i].b)
if temp > max then max = temp
temp = dfs(E[i].a)
if temp > max then max = temp
temp = dfs(E[i].a)
if temp > max then max = temp
if max < min-max
min-max = max
Adjacency-matrix[E[i].a][E[i].b] = 1;
Adjacency-matrix[E[j].a][E[j].b] = 1;
/*The depth first search is called four times but it will terminate one time
if we keep track of the visited vertices because there are only three components*/
/*After the outer loop terminates what we have in min-max will be the answer*/
上述算法需要O(n ^ 3)時間,因為外部循環將運行的邊數為n-1(n-1)! 需要O(n ^ 2)dfs的時間將只訪問每個頂點一次,這樣就是O(n)時間。
但問題是n可能<= 3000且O(n ^ 3)時間對此問題不利。 有沒有其他方法能夠比n ^ 3更快地計算解決鏈接中的問題?
我試圖找到我是否在我的代碼中犯了任何錯誤,但我沒有看到任何錯誤。 任何人都可以請幫助我這里我的代碼給出的答案非常接近正確的答案所以還有什么更多的算法?
@BorisStrandjev,你的算法會在其中一個迭代中選擇i為1,j為2,但是第三部分(3,4)無效。
我終於在我的代碼中犯了錯誤,而不是V [i]存儲i和它存儲V [i]及其祖先的所有后代的總和,否則它將正確地解決上面的例子,感謝大家的幫助。
是的,有更快的方法。
我將需要一些輔助矩陣,我將以正確的方式將它們的創建和初始化留給您。
首先植樹 - 這是圖表的定向。 計算每個頂點的數組VAL[i]
- 頂點及其所有后代的乘客數量(記住我們種植了,所以現在這是有道理的)。 還計算布爾矩陣desc[i][j]
,如果頂點i
是頂點j
后代,則該假設矩陣將為真。 然后執行以下操作:
best_val = n
for i in 1...n
for j in i + 1...n
val_of_split = 0
val_of_split_i = VAL[i]
val_of_split_j = VAL[j]
if desc[i][j] val_of_split_j -= VAL[i] // subtract all the nodes that go to i
if desc[j][i] val_of_split_i -= VAL[j]
val_of_split = max(val_of_split, val_of_split_i)
val_of_split = max(val_of_split, val_of_split_j)
val_of_split = max(val_of_split, n - val_of_split_i - val_of_split_j)
best_val = min(best_val, val_of_split)
執行此循環后,答案將在best_val
。 算法顯然是O(n^2)
你只需要弄清楚如何計算desc[i][j]
和VAL[i]
這樣的復雜性,但它不是那么復雜的任務,我想你可以算出來出去自己
編輯在這里,我將在偽代碼中包含整個問題的代碼。 我故意在OP嘗試之前沒有包含代碼並自行解決:
int p[n] := // initialized from the input - price of the node itself
adjacency_list neighbors := // initialized to store the graph adjacency list
int VAL[n] := { 0 } // the price of a node and all its descendants
bool desc[n][n] := { false } // desc[i][j] - whether i is descendant of j
boolean visited[n][n] := {false} // whether the dfs visited the node already
stack parents := {empty-stack}; // the stack of nodes visited during dfs
dfs ( currentVertex ) {
VAL[currentVertex] = p[currentVertex]
parents.push(currentVertex)
visited[currentVertex] = true
for vertex : parents // a bit extended stack definition supporting iteration
desc[currentVertex][vertex] = true
for vertex : adjacency_list[currentVertex]
if visited[vertex] continue
dfs (currentvertex)
VAL[currentVertex] += VAL[vertex]
perents.pop
calculate_best ( )
dfs(0)
best_val = n
for i in 0...(n - 1)
for j in i + 1...(n - 1)
val_of_split = 0
val_of_split_i = VAL[i]
val_of_split_j = VAL[j]
if desc[i][j] val_of_split_j -= VAL[i]
if desc[j][i] val_of_split_i -= VAL[j]
val_of_split = max(val_of_split, val_of_split_i)
val_of_split = max(val_of_split, val_of_split_j)
val_of_split = max(val_of_split, n - val_of_split_i - val_of_split_j)
best_val = min(best_val, val_of_split)
return best_val
最好的分裂將是{descendants of i} \\ {descendants of j}
, {descendants of j} \\ {descendants of i}
和{all nodes} \\ {descendants of i} U {descendants of j}
。
編輯4:這將無法正常工作!
如果按照3,4,5,6,1,2的順序處理鏈接中的節點, 則在處理6之后(我認為),您將擁有以下集合:{{3,4},{5}, {6}},{{3,4,5},{6}},{{3,4,5,6}},沒有簡單的方法可以再次拆分它們。
我只是留下這個答案,以防其他人想到DP算法。
可能會查看DP算法中所有已處理的鄰居。
。
我正在考慮動態編程算法,其中矩陣是(項目x組的數量)
n = number of sets
k = number of vertices
// row 0 represents 0 elements included
A[0, 0] = 0
for (s = 1:n)
A[0, s] = INFINITY
for (i = 1:k)
for (s = 0:n)
B = A[i-1, s] with i inserted into minimum one of its neighbouring sets
A[i, s] = min(A[i-1, s-1], B)) // A[i-1, s-1] = INFINITY if s-1 < 0
編輯:DP的說明:
這是一個相當基本的動態編程算法。 如果你需要更好的解釋,你應該再讀一遍,這是一個非常強大的工具。
A是矩陣。 行i表示包含所有頂點的圖形。 列c表示具有組數= c的解。
因此A[2,3]
將給出包含項目0,項目1和項目2和3集合的圖形的最佳結果,因此每個集合都在它自己的集合中。
然后從項目0開始,計算每組數量的行(唯一有效的一組是數量= 1),然后使用上面的公式,然后是項目2,等等。
A[a, b]
是所有頂點達到包含和b個集合的最優解。 所以你只需要返回A[k, n]
(包含所有頂點的那個和目標的集合數)。
編輯2:復雜性
O(k*n*b)
其中b是節點的分支因子(假設您使用鄰接列表 )。
由於n = 3
,因此這是O(3*k*b)
= O(k*b)
。
編輯3:確定應該添加哪個相鄰集合的頂點
在結合查找結構中保存n個k元素數組,每個數組都指向該集合的總和。 對於每個新行,要確定可以添加頂點的集合,我們使用其鄰接列表並查找每個鄰居的集合和值。 一旦找到最佳選項,我們就可以將該元素添加到適用的集合中,並通過添加的元素值增加其總和。
你會注意到算法只向下看1行,所以我們只需要跟蹤最后一行(不存儲整個矩陣),並且可以修改前一行的n個數組而不是復制它們。
您可以結合使用二進制搜索和DFS來解決此問題。
這是我將如何進行:
在步驟4中獲得的所有分鍾的最大值是您的答案。 您可以進行額外的簿記以獲得3子圖。
訂單復雜度:N log(Sum)其中Sum是圖的總權重。
我剛剛注意到你已經談到加權頂點,而不是邊緣。 在這種情況下,只需將邊緣視為我的解決方案中的頂點。 它應該仍然有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.