城市之间的最短总距离(最小生成树算法)

求解城市之间的最短总距离是一个非常实际的问题,其大意如下:

某地区由n个城市,如何选择一条路线使各个城市之间的总距离最短?

1.最短总距离算法

先来分析一下上述问题。某个地区的n个城市构成一个交通图,可以使用图结构来描述此问题,其对应关系如下:

  • 每个城市代表图中的一个顶点。
  • 两个顶点间的边即两个城市之间的路径,边的权值代表了城市间的距离。

这样,求解各个城市之间的最短总距离问题就归结为该图的最小生成树问题。

2.最小生成树算法(prim算法)

    //最小生成树算法
    static void PrimGraph(GraphMatrix GM){
        int i,j,k,min,sum;
        int[] weight=new int[GraphMatrix.MaxNum];    //权值
        char[] vtempx=new char[GraphMatrix.MaxNum];        //临时顶点信息
        sum=0;
        for(i=1;i<GM.VertexNum;i++){    //保存邻接矩阵中的一行数据
            weight[i]=GM.EdgeWeight[0][i];
            if(weight[i]==MaxValue){
                vtempx[i]=(char) NoL;
            }else{
                vtempx[i]=GM.Vertex[0];        //邻接顶点
            }
        }
        vtempx[0]=USED;    //选用
        weight[0]=MaxValue;
        for(i=1;i<GM.VertexNum;i++){
            min=weight[0];        //最小权值
            k=i;
            for(j=1;j<GM.VertexNum;j++){
                if(weight[j]<min&&vtempx[j]>0){        //找到具有更小权值的未使用边
                    min=weight[j];        //保存权值
                    k=j;                //保存邻接点序号
                }
            }
            sum+=min;        //权值累加
            System.out.printf("(%c,%c),",vtempx[k],GM.Vertex[k]);   //输出生成树一条边
            vtempx[k]=USED;        //选用
            weight[k]=MaxValue;
            for(j=0;j<GM.VertexNum;j++){    //重新选择最小边
                if(GM.EdgeWeight[k][j]<weight[j]&&vtempx[j]!=0){
                    weight[j]=GM.EdgeWeight[k][j];        //权值
                    vtempx[j]=GM.Vertex[k];
                }
            }
        }
        System.out.printf("\n最小生成树的总权值为:%d\n", sum);
    }

3.程序代码示例如下:

package com.cn.datastruct;

import java.util.Scanner;

//求解城市之间的最短总距离
public class Prim {
    //定义邻接矩阵图结构
    static class GraphMatrix{
        static final int MaxNum=20;  //图的最大顶点数
        char[] Vertex=new char[MaxNum];  //保存顶点信息(序号或字母)
        int GType;      //图的类型(0:无向图,1:有向图)
        int VertexNum;  //顶点的数量
        int EdgeNum;     //边的数量
        int[][] EdgeWeight = new int[MaxNum][MaxNum];  //保存边的权
        int[] isTrav = new int[MaxNum];   //遍历标志
    }

    static final int MaxValue=65535;   //最大值(可设为一个最大整数)
    static final int USED=0;  //已选用顶点
    static final int NoL=-1;  //非邻接顶点
    static Scanner input=new Scanner(System.in);

    //创建邻接矩阵图
    static void CreateGraph(GraphMatrix GM){
        int i,j,k;
        int weight;     //权
        char EstartV,EendV;        //边的起始顶点
        System.out.printf("输入图中各顶点信息\n");
        for(i=0;i<GM.VertexNum;i++){        //输入顶点
            System.out.printf("第%d个顶点:", i+1);
            GM.Vertex[i]=(input.next().toCharArray())[0];  //保存到各顶点的数组元素中
        }
        System.out.printf("输入构成各边的顶点及权值:\n");
        for(k=0;k<GM.EdgeNum;k++){            //输入边的信息
            System.out.printf("第%d条边:", k+1);
            EstartV=input.next().charAt(0);
            EendV=input.next().charAt(0);
            weight=input.nextInt();
            for(i=0;EstartV!=GM.Vertex[i];i++);      //在已有顶点中查找始点
            for(j=0;EendV!=GM.Vertex[j];j++);        //在已有的顶点中查找终点
            GM.EdgeWeight[i][j]=weight;          //对应位置保存权值,表示有一条边
            if(GM.GType==0){        //若是无向图
                GM.EdgeWeight[j][i]=weight;
            }
        }
    }

    //清空矩阵
    static void ClearGraph(GraphMatrix GM){
        int i,j;
        for(i=0;i<GM.VertexNum;i++){
            for(j=0;j<GM.VertexNum;j++){
                GM.EdgeWeight[i][j]=MaxValue;   //设置矩阵中各元素的值为MaxValue
            }
        }
    }

    //输出邻接矩阵
    static void OutGraph(GraphMatrix GM){
        int i,j;
        for(j=0;j<GM.VertexNum;j++){
            System.out.printf("\t%c", GM.Vertex[j]);    //在第一行输出顶点信息
        }
        System.out.println();
        for(i=0;i<GM.VertexNum;i++){
            System.out.printf("%c", GM.Vertex[i]);
            for(j=0;j<GM.VertexNum;j++){
                if(GM.EdgeWeight[i][j]==MaxValue){    //若权值为最大值
                    System.out.printf("\tZ");    //以Z表示无穷大
                }else{
                    System.out.printf("\t%d", GM.EdgeWeight[i][j]);      //输出边的权值
                }
            }
            System.out.println();
        }
    }

    //最小生成树算法
    static void PrimGraph(GraphMatrix GM){
        int i,j,k,min,sum;
        int[] weight=new int[GraphMatrix.MaxNum];    //权值
        char[] vtempx=new char[GraphMatrix.MaxNum];        //临时顶点信息
        sum=0;
        for(i=1;i<GM.VertexNum;i++){    //保存邻接矩阵中的一行数据
            weight[i]=GM.EdgeWeight[0][i];
            if(weight[i]==MaxValue){
                vtempx[i]=(char) NoL;
            }else{
                vtempx[i]=GM.Vertex[0];        //邻接顶点
            }
        }
        vtempx[0]=USED;    //选用
        weight[0]=MaxValue;
        for(i=1;i<GM.VertexNum;i++){
            min=weight[0];        //最小权值
            k=i;
            for(j=1;j<GM.VertexNum;j++){
                if(weight[j]<min&&vtempx[j]>0){        //找到具有更小权值的未使用边
                    min=weight[j];        //保存权值
                    k=j;                //保存邻接点序号
                }
            }
            sum+=min;        //权值累加
            System.out.printf("(%c,%c),",vtempx[k],GM.Vertex[k]);   //输出生成树一条边
            vtempx[k]=USED;        //选用
            weight[k]=MaxValue;
            for(j=0;j<GM.VertexNum;j++){    //重新选择最小边
                if(GM.EdgeWeight[k][j]<weight[j]&&vtempx[j]!=0){
                    weight[j]=GM.EdgeWeight[k][j];        //权值
                    vtempx[j]=GM.Vertex[k];
                }
            }
        }
        System.out.printf("\n最小生成树的总权值为:%d\n", sum);
    }

    public static void main(String[] args) {
        GraphMatrix GM=new GraphMatrix();        //定义保存邻接表结构的图
        char again;
        String go;
        System.out.println("寻找最小生成树!");
        do{
            System.out.print("请先输入生成图的类型:");
            GM.GType=input.nextInt();    //图的种类
            System.out.print("输入图的顶点数量:");
            GM.VertexNum=input.nextInt();        //输入图的顶点数
            System.out.print("输入图的边数量:");
            GM.EdgeNum=input.nextInt();         //输入图边数
            ClearGraph(GM);        //清空图
            CreateGraph(GM);        //生成邻接表结构的图

            System.out.print("最小生成树的边为:");
            PrimGraph(GM);

            System.out.println("\n继续玩吗(y/n)?");
            go=input.next();
        }while(go.equalsIgnoreCase("y"));
        System.out.println("游戏结束!");
    }

}
时间: 2024-12-08 04:44:35

城市之间的最短总距离(最小生成树算法)的相关文章

java通过经纬度计算两个点的之间的距离的算法

通过两个点的经纬度计算距离 从google maps的脚本里扒了段代码,没准啥时会用上.大家一块看看是怎么算的.private const double EARTH_RADIUS = 6378.137;private static double rad(double d){   return d * Math.PI / 180.0;} public static double GetDistance(double lat1, double lng1, double lat2, double ln

最小生成树算法汇总 (普里姆 &amp;&amp; 克鲁斯卡尔与并查集结合)

最小生成树: 今天研究了一下最小生成树,感觉最小生成树算法与最短路算法 相差不大,从Prim 与 Dijskrs算法可以看出 最小生成树即最小权重生成树,主要适用于 N个点之间 构造N-1线路,使N个点之间任意两点之间都可到达, 但是N个点之间 不构成回路,并且这N-1条线路的权重之和最小即 消耗最小. 注意:在构造最小生成树,加入新的节点时,不仅要保证权重最小,首要条件是 不能构成回路. 以图示为例,构造最小生成树 (一)普里姆   以下步骤 (二) 克鲁斯卡尔 最终的最小生成树 和 普里姆一

POJ 3241 Object Clustering 二维平面曼哈顿距离最小生成树

题目链接:点击打开链接 题意: 给定二维平面上的n个点坐标,常数k 下面n行给出坐标 求一个最小生成树,问第k大的边是多少. 任意两个点间建一条边的花费是其曼哈顿距离. 思路:转自:点击打开链接 一.曼哈顿距离最小生成树 曼哈顿距离最小生成树问题可以简述如下: 给定二维平面上的N个点,在两点之间连边的代价为其曼哈顿距离,求使所有点连通的最小代价. 朴素的算法可以用O(N2)的Prim,或者处理出所有边做Kruskal,但在这里总边数有O(N2)条,所以Kruskal的复杂度变成了O(N2logN

最小生成树算法之 Dijkstra算法

Dijkstra算法 Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低. Dijkstra算法是用来求任意两个顶点之间的最短路径.在该算法中,我们用邻接矩阵来存储图.在该程序中设置一个二维数组来存储任意两个顶点之间的边的权值.可以将任意一个图的信息通过键盘输入,让后在输入要查找的两个顶点,程序可以自动求出这两个顶点之间的最短路

数据结构基础温故-5.图(中):最小生成树算法

图的“多对多”特性使得图在结构设计和算法实现上较为困难,这时就需要根据具体应用将图转换为不同的树来简化问题的求解. 一.生成树与最小生成树 1.1 生成树 对于一个无向图,含有连通图全部顶点的一个极小连通子图成为生成树(Spanning Tree).其本质就是从连通图任一顶点出发进行遍历操作所经过的边,再加上所有顶点构成的子图. 采用深度优先遍历获得的生成树称为深度优先生成树(DFS生成树),采用广度优先遍历获得的生成树称为广度优先生成树(BFS生成树).如下图所示,无向图的DFS生成树和BFS

两点之间线段最短,事实真是这样吗?

从小,大人们就告诫我们过马路要直线穿过去,而不要斜插过去,因为这样距离短,就避免了危险.这似乎也印证着两点之间线段最短这句话,同时我也坚信着,两点之间走直线时间最短.直到我见到了下面这张图. 经过无数学霸的论证和科学实验,上图红色路线是最快的路线,此曲线也因此被称为"最速曲线".颠覆思维的一张图,在生活中会给我们什么启示呢? "内圣外王"-做人做事之道 "水至清则无鱼,人至察则无徒",生活中,我们避免不了与人打交道,如果为人太刚硬,太特立独行,势

笔试算法题(50):简介 - 广度优先 &amp; 深度优先 &amp; 最小生成树算法

广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能非递归实现: 相比DFS较快,空间换时间: 适合广度大的图: 空间复杂度:邻接矩阵O(N^2):邻接表O(N+E): 时间复杂度:O(V+E): DFS优缺点: 无论是系统栈还是用户栈保存的节点数都只是树的深度,所以空间耗用小: 有递归和非递归实现: 由于有大量栈操作(特别是递归实现时候的系统调用),执行速度

hdu 1162 Eddy&#39;s picture(最小生成树算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1162 Eddy's picture Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6866    Accepted Submission(s): 3469 Problem Description Eddy begins to like p

[算法系列之二十七]Kruskal最小生成树算法

简介 求最小生成树一共有两种算法,一个是就是本文所说的Kruskal算法,另一个就是Prime算法.在详细讲解Kruskal最小生成树算法之前,让我们先回顾一下什么是最小生成树. 我们有一个带权值的图,我们要求找到一个所有生成树中具有最小权值的生成树.如下图所示,T是图G的生成树.但不是具有最小权值的生成树. 我们可以把他们想象成一组岛屿和连接它们的可能的桥梁.当然修桥是非常昂贵和费时的,所以我们必须要知道建设什么样的桥梁去连接各个岛.不过有一个重要的问题,建设这样一组连接所有岛屿的桥梁的最低价