《演算法導論》習題解答 Chapter 22.1-4(去除重邊)
阿新 • • 發佈:2019-01-25
思路:重開一個新圖,按著鄰接列表的順序從上到下遍歷,每遍歷一行連結串列前,清空visited陣列,如果沒有訪問過這個元素,則加入新圖,如果已經訪問過了(重邊),則不動。
虛擬碼:
複雜度:O(V+E)
for each u 屬於 Vertex visited[u] = false; for u 屬於 Vertex visited[u] = true; for v 屬於 Adj[u] if(!visited[v]) Adj1[u].insert(v); visited[v] = true; for v 屬於 Adj[u] visited[v]=false; visited[u] = false;
證明演算法正確性:
命題:給定一條邊(u,v),此邊為有向邊,visited[v]=false 當且僅當 (u,v)需加入E'.
=>已知起點為u,visited[v]=false,則說明v曾經並沒有被u訪問到,因為如果訪問到,則visited[v]被置為true,則如果當訪問邊(u,v)時,visited[v]==false,則會將(u,v)加入E'中.
<=已知(u,v)需要加入E',如果visited[v]=true,則不會執行if裡的語句,則說明(u,v)不會加入E',與條件矛盾。
輸入:
3 8
a b
a b
a b
b c
b c
b c
c a
c c
原始碼:
package C22; import java.util.Iterator; /** * 化簡多重圖 * @author xiazdong * */ public class C1_4 { static Adjacent_List g; public static void main(String[] args) throws Exception { Adjacent_List adjacent_list = GraphFactory.getAdjacentListInstance("input\\22.1-4.txt"); C1_4.g = adjacent_list; Adjacent_List new_adj = remove_multiedge(adjacent_list); adjacent_list.printAllEdges(); System.out.println("=============="); new_adj.printAllEdges(); } /** * 去掉重邊的函式 * @param g * @return */ public static Adjacent_List remove_multiedge(Adjacent_List g){ int size = g.getSize(); Adjacent_List adj1 = new Adjacent_List(size); boolean visited[] = new boolean[size]; for(int i=0;i<visited.length;i++) visited[i] = false;//O(V) for(int i=0;i<size;i++){ //O(V+E) visited[i] = true; Iterator<String> iter = g.getListByVertexIndex(i).iterator(); while(iter.hasNext()){ String vstr = iter.next(); int v = g.getVertexIndex(vstr); if(!visited[v]){ visited[v] = true; adj1.addEdge(g.getVertexValue(i), vstr); } } /*下面一句話 對新圖遍歷比較快,雖然速度只會提升常數級別。 較快:iter = adj1.getListByVertexValue(g.getVertexValue(i)).iterator(); 較慢:iter = g.getListByVertexIndex(i).iterator(); 因為重邊 */ iter = adj1.getListByVertexValue(g.getVertexValue(i)).iterator(); while(iter.hasNext()){ //再一次遍歷這個連結串列,並對這些元素清除陣列 O(E) String vstr = iter.next(); int v = g.getVertexIndex(vstr); visited[v] = false; } visited[i] = false; } return adj1; } }