问题 F: 最小生成树(Prim)
题目描述
使用Prim算法求图的最小生成树(MST)
输入
每组数据分为两个部分,第一部分为图的点数n,和边数m,
第二部分为m行,每一行输入三个数字,前两个为两个顶点的编号,第三个为边权重。
输出
最小生成树,输出时按照边的两个端点的升序输出。(先看左端点,再看右端点,端点不换位置)
样例输入
3 3
0 1 10
0 2 15
1 2 50
样例输出
0 1 10
0 2 15
解题思路
- 刚开始v集合只有一个结点,我这里用编号为0的结点
- lowcost[i] 代表编号为i的结点到v集合中最少要花费的权值
closeset[i] 代表编号为i的结点到v集合中最近的邻接点- 每一次遍历s集合中的剩余点,找到s集合中到v集合中权值最小的点,将该点加入v集合中
- 更新 lowcost[i] 代表编号为i的结点到v集合中最少要花费的权值
closeset[i] 代表编号为i的结点到v集合中最近的邻接点
源码:
#include <bits/stdc++.h>
using namespace std;
const int cmax = 1e3+5;
typedef long long ll ;
const int INF = 0x3f3f3f3f;
int a[cmax][cmax]; // 邻接矩阵存放无向图
bool vis[cmax]; // vis[i]记录编号为i的结点,有没有在v集合中
struct node {
int start;
int end;
int weight;
}; // 存放每一条边的起点终点以及权值
node res[cmax];
// 边排序比较函数
bool cmp(node m,node n){
if (m.start!=n.start)
return m.start<=n.start;
else
return m.end<=n.end;
}
int flag=0;
void prim(int n){
int lowcost[cmax],closeset[cmax];
// lowcost[i] 代表编号为i的结点到v集合中最少要花费的权值
// closeset[i] 代表编号为i的结点到v集合中最近的邻接点
// -----------------------初始化----------------------------
vis[0]=true; // 刚开始v集合只有一个结点,我这里用编号为0的结点
for (int i = 0; i < n; ++i) {
lowcost[i]=fabs(a[0][i]); // lowcost数组,初始化为0号结点到i号结点的距离
closeset[i]=0; // closeset 数组,初始化为0号结点到i号结点最近
}
// -----------------------寻找最小的代价去v集合--------------------
for (int i = 1; i < n; ++i) {
int j=0;
for (int k = 0; k < n; ++k) {
if (!vis[k]&&lowcost[k]<lowcost[j]){
j=k;
}
}
// printf("%d %d %d\n",closeset[j],j,lowcost[j]);
if (a[closeset[j]][j]>0){
res[flag].start=closeset[j];
res[flag].end=j;
res[flag].weight=lowcost[j];
flag++;
}
else{
res[flag].start=j;
res[flag].end=closeset[j];
res[flag].weight=lowcost[j];
flag++;
}
vis[j]=true;
//---------------------------更新 lowcost[cmax],closeset[cmax]---------
for (int i = 0; i < n; ++i) {
if (!vis[i]&&(a[j][i]<lowcost[i])){
lowcost[i]=fabs(a[j][i]);
closeset[i]=j;
}
}
}
}
int main(){
int n,m;
while (~scanf("%d%d",&n,&m)){
flag=0;
int start,end,weight;
memset(a,INF,sizeof(a));
memset(vis, false,sizeof(vis));
for (int i = 0; i < m; ++i) {
scanf("%d%d%d",&start,&end,&weight);
a[start][end]=weight;
a[end][start]=-1*weight;
}
prim(n);
sort(res,res+flag,cmp);
for (int i = 0; i < flag; ++i) {
printf("%d %d %d\n",res[i].start,res[i].end,res[i].weight);
}
}
return 0;
}