最小生成樹-kruskal演算法(非並查集的實現&優先佇列的sh xian&並查集的實現)
阿新 • • 發佈:2018-11-09
kruskal演算法:構造一個只含n個頂點,而邊集為空的子圖,若將該子圖中各個頂點看成是各棵樹的根節點,則它是一個含有n棵樹的森林 。之後,從網的邊集中選取一條權值最小的邊,若該邊的兩個頂點分屬不同的樹 ,則將其加入子圖,也就是這兩個頂點分別所在的 兩棵樹合成一棵樹;反之,若該邊的兩個頂點已落在同一棵樹上,則不可取,而應該取下一條權值最小的邊再試之。依次類推,直至森林只有一棵樹。kruskal演算法能夠在並查集的基礎很快的實現。結合例子來介紹具體演算法實現(其中並查集的部分可以詳見並查集介紹部分) http://poj.org/problem?id=1251
非並查集的實現
import java.util.*; public class kruskal { public static void main(String args[]){ Scanner in=new Scanner(System.in); while(in.hasNext()){ int V=in.nextInt(); int E=in.nextInt(); List<Eg> eg=new ArrayList<Eg>();//用於儲存邊 for(int i=0;i<E;i++){ int x=in.nextInt(); int y=in.nextInt(); int value=in.nextInt(); //去除重複邊 int flag1=1; for(int j=0;j<eg.size();j++){ if(eg.get(j).x==x &&eg.get(j).y==y){ if(value<eg.get(j).value){ eg.get(j).setValue(value); } flag1=0; break; } } if(flag1==1){ eg.add(new Eg(x,y,value)); } } //MST演算法 List<Eg> ans=new ArrayList<Eg>(); int visit[]=new int[V+1]; for(int i=0;i<V-1;i++){ int posi=-1; int posj=-1; int mineg=Integer.MAX_VALUE; for(int j=0;j<eg.size();j++){ Eg temp1=eg.get(j); if(visit[temp1.x]==0 || visit[temp1.y]==0){ if(temp1.value<mineg){ posi=temp1.x; posj=temp1.y; mineg=temp1.value; } } } visit[posi]=1; visit[posj]=1; ans.add(new Eg(posi,posj,mineg)); } //列印結果 for(int i=0;i<ans.size();i++){ Eg temp2=ans.get(i); System.out.println(temp2.x+" "+temp2.y+" "+temp2.value); } } } } //定義好邊的資料結構 class Eg{ int x; int y; int value; Eg(int x,int y,int value){ this.x=x; this.y=y; this.value=value; } public void setValue(int value){ this.value=value; } 優先佇列的實現:
import java.util.*; public class kruskal_queue { public static void main(String args[]){ Scanner in=new Scanner(System.in); while(in.hasNext()){ int V=in.nextInt(); int M=in.nextInt(); Map<String,Integer> map=new HashMap<String,Integer>(); //map用於查詢比較快 Queue<E> queue=new PriorityQueue<E>(new Comparator<E>() { @Override public int compare(E o1, E o2) { return o1.value-o2.value; } }); for(int i=0;i<M;i++){ int x=in.nextInt(); int y=in.nextInt(); //考慮無向圖,統一將小頂點放在前面,大頂點放在後面 int xx=x; int yy=y; x=Math.min(xx,yy); y=Math.max(xx,yy); int value=in.nextInt(); if(map.containsKey(x+" "+y)){ if(map.get(x+" "+y)>value){ map.remove(x+" "+y); map.put(x+" "+y,value); } }else{ map.put(x+" "+y,value); } } for(String key:map.keySet()){ String str[]=key.split(" "); queue.offer(new E(Integer.valueOf(str[0]),Integer.valueOf(str[1]),map.get(key))); } int visit[]=new int[V+1]; List<E> ans=new ArrayList<E>(); int cnt=0; while(queue.size()>0){ E temp4=queue.poll(); if(visit[temp4.x]==0 || visit[temp4.x]==0){ ans.add(temp4); cnt++; if(cnt==V-1) break; } } for(int i=0;i<ans.size();i++){ E temp5=ans.get(i); System.out.println(temp5.x+" "+temp5.y+" "+temp5.value); } } } } //使用優先佇列實現卡路斯卡爾演算法 class E{ int x; int y; int value; E(int x,int y,int value){ this.x=x; this.y=y; this.value=value; } public void setValue(int value){ this.value=value; } }