Prime

//Prime算法
/*
在求解最小生成树的问题中,不管是Prime算法还是Kruskal算法,都需要了解
切割定理,因为这两个算法的核心思想都利用了切割定理
切割定理 
*/ 
#include <queue>
#include<iostream>
#include<stdlib.h>
#include<map>
#include<fstream>
#define max 20

using namespace std;

typedef struct VNode{
	int data;
	map<int,int> mp;//map key 是节点号,即该节点到key之间有一条边,权重是value 
}VN;

typedef struct Graph{
	int v,e;
	VN ag[max];
}G;

typedef struct WeightedEdge{//Prime算法里是需要单独的结构体来储存边的,因为涉及到横向边的
    						//比较,和顶点的问题
	int v,d,w;
	friend bool operator < (const WeightedEdge &e1,const WeightedEdge &e2){
		return e1.w > e2.w;
	}
}E;
bool visited[max] = {false};//true表示是最小生成树里的节点,false表示还未加入到最小生成树里 
priority_queue<E> q;//最小堆,用来存储横向边 
int mst[max] = {0};//用来存储最小生成树 mst[i] == j; 表示i顶点的父亲节点是j 
int sum;//权重之和 
void initG(G* g);
int Prime(G* g, int v);

int main(){
	G* g = new G;
	initG(g);
	sum = Prime(g,0);
	cout<<sum<<endl;
	for(int i = 0; i < g->v; i++){
		cout<< i <<" " << mst[i] <<endl;
	}

	return 0;
} 

void initG(G* g){
	ifstream infile;//输入流
	infile.open("Prime.txt",ios::in); 
	if(!infile.is_open()){
		cout << "Flie open failure" <<endl;
		return;
	}
 
	infile >> g->v >> g->e ;
	
	//Input the edge and weight
	for(int i = 0; i < g->e; i++){
		int node1, node2, w;
		infile >> node1 >> node2 >> w;
		g->ag[node1].mp[node2] = w; 
		g->ag[node2].mp[node1] = w; //无向图
	}
	
	infile.close();
}

int Prime(G*g,int v){
	int cur = v;//加入新节点 ,这个当前节点的意思是新加入已选顶点集合的点,又因为之前已选集合
    			//的点所有的边都已经加入到最小堆中,只有这个刚刚加入的顶点所对应的边没有加入					//到最小堆中,所以只需要处理当前节点就可以了。
	mst[v] = v;
	visited[cur] = true; //将cur顶点加入最小生成树中
	int count = g->v;
	int sum = 0;
	
	while(count--){//每次都只加入一个顶点,一共有count个顶点,循环count次
		E e;
		//将cur顶点的边全部存入到最小堆中,因为cur已经加入已选集合中了,新增的横向边都是cur
        //的邻边
		for(map<int,int>::iterator it = g->ag[cur].mp.begin();it != g->ag[cur].mp.end(); it++){
			e.v = cur;
			e.d = it->first;
			e.w = it->second;
			q.push(e);
		}
		while(!q.empty() && visited[q.top().v] && visited[q.top().d]){//如果这个top的左右两个顶点都在已选顶点集合,那么这条在已选集合内部了,这条边再不会是横切边 
			q.pop();//将其删去	
		}
		if(!q.empty()){//取出最短的横切边
			e = q.top();
			sum += e.w;
            //如果e.v在已选集合中,那么e.v为父节点,另一个为子节点
			if(visited[e.v]){
				mst[e.d] = e.v;
				cur = e.d;
			} else {
				mst[e.v] = e.d;
				cur = e.v;
			}
			visited[cur] = true; //将cur顶点加入最小生成树中
			q.pop();//将其删除 
		}
	}
	return sum;
}

`

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值