DS图—最小生成树(附思路解析)

题目描述
根据输入创建无向网。分别用Prim算法和Kruskal算法构建最小生成树。(假设:输入数据的最小生成树唯一。)

输入
顶点数n

n个顶点

边数m

m条边信息,格式为:顶点1 顶点2 权值

Prim算法的起点v

输出
输出最小生成树的权值之和

对两种算法,按树的生长顺序,输出边信息(Kruskal中边顶点按数组序号升序输出)

样例输入
6
v1 v2 v3 v4 v5 v6
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6
v1
样例输出
15
prim:
v1 v3 1
v3 v6 4
v6 v4 2
v3 v2 5
v2 v5 3
kruskal:
v1 v3 1
v4 v6 2
v2 v5 3
v3 v6 4
v2 v3 5

两种方法需要用到不同的存储方法
推荐一个b站的up主懒猫老师的数据结构视频
在这里插入图片描述

在这里插入图片描述
文章链接https://www.bilibili.com/read/cv8013121

#include<iostream>
#include<cstring>
using namespace std;

#define maxx  100
string name[maxx];

class EdgeType{
	public:
	int from,to;
	int weight;
	EdgeType(){
		from = to = 0;
		weight=1000000;
	}
	EdgeType(const EdgeType &e){
		from = e.from;
		to = e.to;
		weight = e.weight;
	}
};

class Kruskal{
	private:
		EdgeType edge[maxx*maxx];
		int n,side,cnt;
		int parent[maxx];
	public:
		Kruskal(int num,int s){
			n = num;
			side = s;
			cnt = 0;
		}
		void insert(int a,int b,int weight){
			edge[cnt].from = a;
			edge[cnt].to = b;
			edge[cnt].weight = weight; 
			cnt++;
		}
		void sort(){
			for(int i = 0; i < side - 1; i++){
				for(int j = i + 1; j < side; j++){
					if(edge[j].weight < edge[i].weight){
						EdgeType temp(edge[j]);
						edge[j] = edge[i];
						edge[i] = temp;
					}					
				}				
			}	
		}
		int findParent(int v){
			while(parent[v] > -1){
				v = parent[v];
			}
			return v;
		}
		void outputMST(int i){
			if(name[edge[i].from] > name[edge[i].to])
				cout<<name[edge[i].to]<<" "<<name[edge[i].from]<<" "<<edge[i].weight<<"\n";	
			else
				cout<<name[edge[i].from]<<" "<<name[edge[i].to]<<" "<<edge[i].weight<<"\n";	
			return ;
		}
		void func(){
			sort();
			cout<<"kruskal:\n";
			for(int i; i < n; i++){
				parent[i] = -1;
			}	
			for(int num = 0, i =0; i < side; i++){
				int vex1 = findParent(edge[i].from);
				int vex2 = findParent(edge[i].to);
				if(vex1 != vex2){
					outputMST(i);
					parent[vex2] = vex1;
					num++;
					if(num == n - 1){
						return ;
					}
				}
				
			}
		}
};

int find(string a,int n) {
	for (int i = 0; i < n; i++) {
		if(a == name[i]){
			return i;
		}
	}
}
struct shortEdge {
	int lowcost;
	int adjvex;
};

class Prim {
	private:
		int map[maxx][maxx];
		int n;
	public:
		Prim(int input_n) {
			n = input_n;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					map[i][j] = 1000000;
				}
			}
		}
		void insert(int a,int b,int weight) {
			map[a][b] = weight;	
			map[b][a] = weight;	
		}
		int minEdge(shortEdge *s,int n) {
			int min = 1000000,k = 0;
			for(int i = 0; i < n; i++) {
				if(s[i].lowcost != 0 && s[i].lowcost < min) {
					min = s[i].lowcost;
					k = i;
				}
			}
			return 	k;
		}
		void func(int d) {
			int start = d,sum = 0,k = 0;
			shortEdge s[n];
			//---------第一遍算权值和-----------
			for(int i = 0; i < n; i++) {
				s[i].lowcost = map[start][i];
				s[i].adjvex = start;
			}
			s[start].lowcost = 0;
			for(int i = 0; i < n - 1; i++) {
				k = minEdge(s,n);
				sum += s[k].lowcost;
				s[k].lowcost = 0;
				for(int j = 0; j < n; j++) {
					if(map[k][j] < s[j].lowcost) {
						s[j].lowcost = map[k][j];
						s[j].adjvex = k;
					}
				}
			}
			cout<<sum<<endl;
			//---------第二遍输出节点关系-----------
			cout<<"prim:"<<"\n";
			for(int i = 0; i < n; i++) {
				s[i].lowcost = map[start][i];
				s[i].adjvex = start;
			}
			s[start].lowcost = 0;
			for(int i = 0; i < n - 1; i++) {
				k = minEdge(s,n);
				cout<<name[s[k].adjvex]<<" "<<name[k]<<" "<<s[k].lowcost<<endl;
				s[k].lowcost = 0;
				for(int j = 0; j < n; j++) {
					if(map[k][j] < s[j].lowcost) {
						s[j].lowcost = map[k][j];
						s[j].adjvex = k;
					}
				}
			}
		}
};


int main() {
	int  num,side,weight;
	string name1,name2;
	cin >> num;

	for(int i = 0; i < num; i++) {
		cin>>name[i];
	}
	cin>>side;
	Prim p(num);
	Kruskal k(num,side);
	while(side--) {
		cin>>name1>>name2>>weight;
		int a = find(name1,num), b = find(name2,num);
		p.insert(a,b,weight);
		k.insert(a,b,weight);
	}
	string s;
	cin >>s;
	int d = find(s,num);
	p.func(d);
	k.func();
	return 0;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值