算法复习(一)——最小生成树

求最小生成树可以使用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();
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值