算法複習(一)——最小生成樹

求最小生成樹可以使用Prim或Kruskal算法

Kruskal比較直觀,因爲邊是按全局從小到大依次考慮的,所以能保證全局最優解。若不構成環,則加入這條邊;否則,丟棄這條邊。因爲出現環,說明當前已經有邊將該點加入生成樹,而越先考慮的邊代價是最小的。

Prim也是個貪心算法,但證明不太直觀。

下面是hdu 1875的java解

採用Kruskal算法,複雜度爲O(eloge),效率通常情況下都比Prim要高

使用並查集,帶路徑壓縮,所以每次集合方面的操作代價幾乎是常數

這題要使用double類型才能過!,還有回車符號得是/r/n.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Point {
    private int x;
    private int y;
    private int id;
    private Point parent = this;
    
    
    public Point(int newId) {
        this.id = newId;
        this.x = -1;
        this.y = -1;
    }
    
    public Point(int newX, int newY) {
        this.x = newX;
        this.y = newY;
        this.id = -1;
    }
    
    
    final public int getX() {
        return this.x;
    }
    
    final public int getY() {
        return this.y;
    }
    
    final public int getId(){
        return this.id;
    }
    
    public Point getParent() {
        return this.parent;
    }
    
    public void setParent(Point newParent) {
        this.parent = newParent;
    }
    
}

class Edge {
    Point point1;
    Point point2;
    double weight;
    
    public Edge(){    
    }
    
    public Edge(Point newPoint1, Point newPoint2) {
        this.point1 = newPoint1;
        this.point2 = newPoint2;
        this.weight = calWeight(this.point1, this.point2);
    }
    
    public Edge(int start, int end, double newWeight) {
        this.point1 = new Point(start);
        this.point2 = new Point(end);
        this.weight = newWeight;
    }
    
    public double calWeight(Point point1, Point point2) {
        int x1 = point1.getX();
        int y1 = point1.getY();
        int x2 = point2.getX();
        int y2 = point2.getY();
        return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
    }
    
    public Point getPoint1(){
        return point1;
    }
    
    public Point getPoint2(){
        return point2;
    }
    
    public double getWeight() {
        return weight;
    }
}

class MST {
    private ArrayList<Point> points;
    private ArrayList<Edge> edges;
    private double cost = 0;
    
    public MST() {
        
    }

    public MST(int newSize, boolean isEdge) {
        if(!isEdge) {
            this.points = new ArrayList<Point>(newSize);
            this.edges = new ArrayList<Edge>();
        } else {
            this.edges = new ArrayList<Edge>(newSize);
        }
    }
    
    final public void addPoint(Point newPoint){
        this.points.add(newPoint);
    }
    
    final public void addEdge(Point point1, Point point2) {
        Edge tmp = new Edge(point1, point2);
        if(tmp.getWeight() >= 10 && tmp.getWeight() <= 1000) {
            this.edges.add(tmp);
        }
    }
    
    final public void addEdge(int start, int end, double weight) {
        this.edges.add(new Edge(start, end, weight));
    }
    
    final public void buildEdges() {
        for(int i = 0; i < points.size(); i++) {
            for(int j = i+1; j < points.size(); j++) {
                Point u = points.get(i);
                Point v = points.get(j);
                addEdge(u, v);
            }
        }
    }
    
    public double kruskal() {
        Collections.sort(this.edges, new Comparator<Edge>() {
            @Override
            public int compare(Edge edge1, Edge edge2) {
                double w1 = edge1.getWeight();
                double w2 = edge2.getWeight();
                if(w1 > w2) {
                    return 1;
                } else {
                    return -1;
                }
            }
        });
//        for(Edge e : this.edges) {
//            System.out.println(e.getWeight());
//        }
        
        for(int i = 0; i < this.edges.size(); i++) {
            Edge edge = edges.get(i);
            Point point1 = edge.getPoint1();
            Point point2 = edge.getPoint2();
            Point parent1 = findParent(point1);
            Point parent2 = findParent(point2);
            if(parent1 != parent2) {
                this.cost += edge.getWeight();
                parent2.setParent(parent1);
            }

        Point theParent = findParent(points.get(0));
        for(int i = 1; i < this.points.size(); i++) {
            Point tmpPoint = points.get(i);
            if(findParent(tmpPoint) != theParent) {
                return -1;
            }
        }
        return this.cost;
    }
    
    public Point findParent(Point x) {
        Point parent = x.getParent();
        if( parent != x)  {
            Point newParent = findParent(parent);
            x.setParent(newParent);
            return newParent;
        } else {
            return parent;
        }
    }
    
    public double getCost() {
        return this.cost;
    }
}

public class Main {
    
    public static void main(String[] args) throws IOException {

        int T, nodeCnt, x, y;
        StreamTokenizer in = new StreamTokenizer(
                new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        in.nextToken();
        T = (int)in.nval;
        for(int i = 0; i < T; i++) {
            in.nextToken();
            nodeCnt = (int)in.nval;
            MST mst = new MST(nodeCnt, false);
            for(int j = 0; j < nodeCnt; j++) {
                in.nextToken();
                x = (int)in.nval;
                in.nextToken();
                y = (int)in.nval;
                mst.addPoint(new Point(x,y));
            }
            mst.buildEdges();
            double res = mst.kruskal();
            if(res != -1) {
                out.printf("%.1f\r\n", 100*res);
            } else {
                out.println("oh!");
            }
//            out.flush();
        }
        out.flush();
    }
}

点赞