1399 最小生成树
-
描述: 最小生成树问题是实际生产生活中十分重要的一类问题。假设需要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,自然需要考虑这样一个问题,即如何在最节省经费的前提下建立这个通信网。
可以用连通网来表示n个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。现在,需要选择一棵生成树,使总的耗费最小。这个问题就是构造连通网的最小代价生成树,简称最小生成树。一棵生成树的代价就是树上各边的代价之和。
而在常用的最小生成树构造算法中,普里姆(Prim)算法是一种非常常用的算法。
在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法建立最小生成树,并输出最小生成树的代价。 -
输入:输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数,对于第i行的第j个整数,如果不为0,则表示第i个顶点和第j个顶点有直接连接且代价为相应的值,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图,且保证图中只有一个连通分量。 -
输出:只有一个整数,即最小生成树的总代价。请注意行尾输出换行。
-
输入示例
4 0 2 4 0 2 0 3 5 4 3 0 1 0 5 1 0
-
输出示例
6
-
代码块
#include<bits/stdc++.h> using namespace std; #define inf 9999 #define NotAVertex (-1) const int N = 51; int VexNum;//顶点的数目 //《数据结构与算法分析》中关于prim的代码(其实都一样) typedef int Vertex;//顶点的类型 typedef struct TableEntry{ int adj[N];//此顶点连接到的点的权值 int Known;//此顶点是否为已知 int Dist;//Dv表示连接v到已知顶点最短边的权 Vertex Path;//Pv表示导致Dv改变的最后的顶点 }Table[N];//每个顶点都带有此三种信息 // table表初始状态: ==> v0加入生成树 // v Known Dv Pv v Known Dv Pv // v0 0 inf -1 v0 1 0 0 // v1 0 inf -1 ==> v1 0 4 0 // v2 0 inf -1 v2 0 2 0 // v3 0 inf -1 v3 0 inf 0 void InitTable(Table &T){ int n; scanf("%d", &n); VexNum = n; for(int i=0; i<n; ++i){ for(int j=0; j<n; ++j){ scanf("%d", &T[i].adj[j]); if(i!=j && T[i].adj[j]==0){ T[i].adj[j] = inf; } } } for(int i=0; i<n; ++i){ T[i].Known = 0; T[i].Dist = inf; T[i].Path = NotAVertex; } } int Prim(Table &T){ //初始化表 InitTable(T); int cost = 0; //将第一个点加入生成树(随便一个点,这里用第0个点) T[0].Known = 1; for(Vertex i=0; i<VexNum; ++i){ T[i].Dist = T[i].adj[0];//其他点到0的距离 T[i].Path = 0;//引起Di该边的点都是0 } for(int i=1; i<VexNum; ++i){//共循环VexNum-1次才能保证每个顶点都遍历一遍 int min = inf; Vertex V;//V是选中的点(smallest unknow distance vertex) for(Vertex j=0; j<VexNum; ++j){ if(T[j].Known==0 && T[j].Dist<min){ V = j; min = T[j].Dist; } } T[V].Known = 1;//标记V已经加入生成树 cost = cost + min; //更新未标记的集合(know == 0)到已标记的集合(Know == 1)的最短距离,其实就是刚加入点的影响 Vertex W; for(W=0; W<VexNum; ++W){ if(T[W].Known==0 && T[W].adj[V]<T[W].Dist){//未标记的顶点到V的距离比未标记的顶点到已知顶点(除V以外)小 T[W].Dist = T[W].adj[V]; T[W].Path = V;//V是引起Dw变化的点 } } } return cost; } int main(){ Table T; printf("%d\n", Prim(T)); system("pause"); return 0; }