//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;
}
`