1. 程式人生 > >最小生成樹-kruskal演算法(非並查集的實現&優先佇列的sh xian&並查集的實現)

最小生成樹-kruskal演算法(非並查集的實現&優先佇列的sh xian&並查集的實現)

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;
    }
}