最小生成树(Kruskal和Prim算法)
描述
分别使用prim和kruskal算法实现最小生成树
输入
格式:
第一行两个整数n,e。n (2000001≤n≤200000) 代表图中点的个数,e (5000000≤m≤500000) 代表边的个数。
接下来e行,每行代表一条边:i j w 表示顶点i和顶点j之间有一条权重为w的边
输出
最小生成树所有边的权重和
- test 13-1
#include<iostream>
#include<vector>
using namespace std;
struct edge
{
long long to;
long long w;
};
struct edge1
{
long long w;
long long v;
edge1(){}//注意默认构造函数一定要写
edge1(int w1,int v1){
w=w1,v=v1;
}
bool operator < (const edge1& b) const
{
return w < b.w;
}
bool operator <= (const edge1& b) const
{
return w <= b.w;
}
bool operator > (const edge1& b) const
{
return w > b.w;
}
};
vector<edge> edges[200005];//可用链表数组代替
bool lowcost[200005];
//接下来是最小堆的实现
template<class T>
void changeLength1D(T*& a, int oldLength, int newLength)
{
T* temp = new T[newLength];
int number = min(oldLength, newLength);
copy(a, a + number, temp);
delete[] a;
a = temp;
}
template<class T>
class minHeap
{
public:
minHeap(int initialCapacity = 10);
~minHeap() { delete[] heap; }
bool empty() const { return heapSize == 0; }
int size() const
{
return heapSize;
}
const T top()
{
return heap[1];
}
void pop();
void push(const T&);
void initialize(T*, int);
void deactivateArray()
{
heap = NULL; arrayLength = heapSize = 0;
}
private:
int heapSize;
int arrayLength;
T* heap;
};
template<class T>
minHeap<T>::minHeap(int initialCapacity)
{
arrayLength = initialCapacity + 1;
heap = new T[arrayLength];
heapSize = 0;
}
template<class T>
void minHeap<T>::push(const T& theElement)
{
if (heapSize == arrayLength - 1)
{
changeLength1D(heap, arrayLength, 2 * arrayLength);
arrayLength *= 2;
}
int currentNode = ++heapSize;
while (currentNode != 1 && heap[currentNode / 2] > theElement)
{
heap[currentNode] = heap[currentNode / 2];
currentNode /= 2;
}
heap[currentNode] = theElement;
}
template<class T>
void minHeap<T>::pop()
{
heap[1].~T();
T lastElement = heap[heapSize--];
int currentNode = 1,
child = 2;
while (child <= heapSize)
{
if (child < heapSize && heap[child] > heap[child + 1])
child++;
if (lastElement <= heap[child])
break;
heap[currentNode] = heap[child];
currentNode = child;
child *= 2;
}
heap[currentNode] = lastElement;
}
class Prime{
public:
void initialize(){
cin >> n >> e;
for( int i = 0; i <= n; ++i)
lowcost[i] = true;//用来判断是否该点已经加入
for(int i = 1; i <= e; ++i)
{
long long v1, v2, w;
cin >> v1 >> v2 >> w;
edge e1,e2;
e1.w=w,e2.w=w;
e1.to=v2,e2.to=v1;
edges[v1].push_back(e1);
edges[v2].push_back(e2);
}
}
void prim()
{
long long s = edges[1].size();//获取第一个数组的长度
minHeap<edge1> q;
lowcost[1] = 0;
for(int i = 0; i < s; ++i)//初始化相邻点
{
long long v = edges[1][i].to, w = edges[1][i].w;
edge1 temp(w,v);
q.push(temp);
}
for(int i = 1; i <= n - 1; ++i)
{
long long min, toVetx;
while(lowcost[q.top().v] == 0)//最小堆中会加入多余的边,判断是否该点是否已经加入
q.pop();
min = q.top().w;
toVetx = q.top().v;
q.pop();
result += min;//更新结果
lowcost[toVetx] = 0;
s = edges[toVetx].size();
for(int j = 0; j < s; ++j)//遍历新加入的边的邻接点
{
long long v = edges[toVetx][j].to, w = edges[toVetx][j].w;
if(lowcost[v])//如果该点未被加入点集
{
edge1 temp(w,v);
q.push(temp);
}
}
}
cout<<result;
}
private:
long long result=0;
int n,e; //顶点和边数
};
int main()
{ Prime P;
P.initialize();
P.prim();
return 0;
}
- test 13-2
#include<iostream>
using namespace std;
int pre[200010];//记录所有节点的父节点
struct node
{ long long dis;
int from,to;
}edge[500010];
void quickSort(node *array,int low,int high){
if(low>high) return;
int i,j;node index;
index=array[low];i=low;j=high;
while(i<j){
while(i<j&&array[j].dis>=index.dis)
j--;
if(j>i) array[i++]=array[j];
while(i<j&&array[i].dis<index.dis)
i++;
if(j>i) array[j--]=array[i];
}
array[i]=index;
quickSort(array,low,i-1);
quickSort(array,i+1,high);
}
int find(int x)
{
int root=x;
while(root!=pre[root]) root=pre[root];//找到根
while(x!=root){//压缩路径 所有的子节点都指向根
int temp=pre[x];
pre[x]=root;
x=temp;
}
return root;
}
void join(int x,int y)//将y祖父节点指向x的祖父节点
{
pre[find(y)]=find(x);
}
int main()
{ long long sum;
int n,m,k=0;
cin>>n>>m;
for(int i=1;i<=m;i++)
{ cin>>edge[i].from>>edge[i].to>>edge[i].dis;
int temp=0;
if(edge[i].from>edge[i].to){//按照顺序存储
temp=edge[i].from;
edge[i].from=edge[i].to;
edge[i].to=temp;
}
}
for(int i=1;i<=n;i++)
pre[i]=i;//初始化自身为一个类
quickSort(edge,1,m);
for(int i=1;i<=m;i++)//遍历所有的边
{
if(k==n-1) break;//满足条件退出
if(find(edge[i].from)!=find(edge[i].to))//如果不是一个集合
{
join(edge[i].from,edge[i].to);//合并
sum+=edge[i].dis;//记录边权
k++;//已连接边数+1
}
}
cout<<sum;
return 0;
}