【问题描述】
已知含有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;
}