最小生成树的权值之和-Prim算法

【问题描述】
已知含有n个顶点的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出,只给出不包括主对角线元素在内的下三角形部分的元素,且不包括不相邻的顶点对。请采用Prim算法,求该连通图从1号顶点出发的最小生成树的权值之和。
【输入形式】
第一行给出结点个数n和三元组的个数count,以下每行给出一个三元组,数之间用空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
求解的最小生成树的各条边、边的权值之和
【样例输入】
5 8
2 1 7
3 1 6
3 2 8
4 1 9
4 2 4
4 3 6
5 2 4
5 4 2
【样例输出】

1-3:6
3-4:6
4-5:2
4-2:4
18

【样例说明】
权值是正整数,可能很大,但不需要考虑整型溢出问题

以下为本人学习数据结构时写的代码,比较的长,后面有自己重写的较短的代码供大家查阅

#include
#define maxsize 100
using namespace std;
int graph[maxsize][maxsize];
int ans = 0;//MST权值之和
struct Node
{
	int v;//顶点
	bool isSelect;//是否选中
	int distance;//到集合的距离
	int adj;//邻接顶点
};
void initMST(Node MST[], int n)
{
	for (int i = 1; i <= n; i++)
	{
		MST[i].v = i;
		MST[i].distance = graph[i][1];
		if (i == 1) MST[i].isSelect = true;
		else MST[i].isSelect = false;
		MST[i].adj = 1;
	}
}
bool isAllSelect(Node MST[], int n)
{
	for (int i = 1; i <= n; i++)
	{
		if (MST[i].isSelect == false) return false;
	}
	return true;
}
void searchMinDistanceNode(Node MST[], int n,int &v1,int &v2)
{
	int min = MST[1].distance;
	for (int i = 1; i <= n; i++)
	{
		if (MST[i].isSelect) continue;
		for (int j = 1; j <= n; j++)
		{
			if (MST[j].isSelect)
			{
				if (graph[i][j]< min)
				{
					v1 = j;
					v2 = i;
					min = graph[i][j];
				}
			}
		}
	}
	MST[v2].isSelect = true;
	MST[v2].distance = min;//更新被选择的节点的距离
	MST[v2].adj = v1;//更新被选择节点的邻接点
}
void updateMST(Node MST[], int n)
{
	for (int i = 1; i <= n; i++)
	{
		if (MST[i].isSelect) continue;
		for (int j = 1; j <= n; j++)
		{
			if (MST[j].isSelect)
			{
				if (graph[i][j] < MST[i].distance)
				{
					MST[i].distance = graph[i][j];//更新距离
					MST[i].adj = j;//更新邻接节点
				}
			}
		}
	}
}
int main()
{
	fill(graph[0], graph[0] + maxsize * maxsize, 32767);
	int n,count;//节点个数和三元组个数
	cin >> n >> count;
	for (int i = 1; i <= count; i++)//给关系矩阵赋初值
	{
		int e1, e2, e3;
		cin >> e1 >> e2 >> e3;
		graph[e1][e2] = e3;graph[e2][e1] = e3;
	}
	Node MST[maxsize];
	initMST(MST, n);
	while (!isAllSelect(MST, n))
	{
		int v1, v2;//距离最近的两个邻接点 v1是距离最近的节点,v2是被选择的节点
		searchMinDistanceNode(MST,n,v1,v2);
		cout << v1 << "-" << v2 << ":" << MST[v2].distance << endl;
	    updateMST(MST, n);//更新没有被选择的节点到被选择节点集合的距离
		ans += MST[v2].distance;
	}
	cout << ans << endl;
	//system("pause");
	return 0;
}

以下为朴素未优化版本,堆优化版本连接:https://blog.csdn.net/weixin_55085530/article/details/120391233

//时间复杂度O(n^2)可解决图中可能存在重边和自环,边权可能为负数
#include
#define N 1000000
using namespace std;
int n,m,cnt,vis[N],dist[N],head[N],ans;
typedef pair<int,int>PII;
struct edge
{
    int to,next,weight;
}e[N];
void add(int u,int v,int w)
{
    e[++cnt].to=v;
    e[cnt].weight=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void Prim()
{
     memset(dist,0x3f,sizeof(dist));
    dist[1]=-0x3f3f3f3f;
    for(int i=1;i<=n-1;i++)
    {
        int t=-1;//选取距离MST最小的点
        for(int i=1;i<=n;i++){
            if(!vis[i]&&(t==-1||dist[i]<dist[t])){
                t=i;
            }
        } 
        vis[t]=1;
        for(int i=head[t];i;i=e[i].next){
            if(!vis[e[i].to]){//更新其他未并入MST集合的点到集合的距离 
                dist[e[i].to]=min(dist[e[i].to],e[i].weight);
            } 
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    Prim();
    for(int i=1;i<=n;i++)
    {
        if(dist[i]==0x3f3f3f3f)
        {
            cout<<"impossible";
            exit(0);
        }
    }
    for(int i=2;i<=n;i++) ans+=dist[i];
    cout<<ans;
    return 0;
}

你可能感兴趣的:(数据结构,数据结构,树结构,prim)