题目描述
给出一个矩阵,要求以矩阵方式单步输出最小生成树生成过程。要求先输出Prim生成过程(以点0作为起始点),再输出Kruskal,每个矩阵输出后换行。注意,题中矩阵表示无向图
输入
结点数
矩阵
输出
Prim:
矩阵输出
Kruskal:
矩阵输出
样例输入
3
0 1 3
1 0 2
3 2 0
样例输出
Prim:
0 0 0
0 0 0
0 0 0
0 1 0
1 0 0
0 0 0
0 1 0
1 0 2
0 2 0
Kruskal:
0 0 0
0 0 0
0 0 0
0 1 0
1 0 0
0 0 0
0 1 0
1 0 2
0 2 0
代码如下:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <assert.h>
using namespace std;
int defaultNumVertices = 100;
int defaultWeight=0;
int maxWeight=0x7fffffff;
#define defaultSize 100
template <typename T>
class MinHeap
{
private:
T* heap;
int currentSize;
int maxHeapSize;
void SiftDown(int start,int m)
{
/*删除顶点,做法是数组最前面的和最后面的
互换,然后最大长度减一,然后调整顺序,这时要>=下滑*/
int i=start;//start=0,从零开始
int j=2*i+1;//j为下方的
T temp = heap[i];
while(j<=m)//m为最后位置
{
if(j<m && heap[j]>heap[j+1])//得到较小孩子的位置
j++;
if(temp<heap[j])//小于后面的停止,等于也要下滑
break;//加=75,不加50
else
{
heap[i]=heap[j];
i=j;
j=2*j+1;
}
}
heap[i]=temp;
}
void SiftUp(int start)
{
int j=start;
int i=(j-1)/2;
T temp = heap[j];//temp当前节点
while(j>0)
{
//if(heap[i]<=temp),后面的重载操作符也要修改
if(heap[i]<temp)
break;
else//如果temp<上个顶点则,上滑
{
heap[j]=heap[i];
j=i;
i=(j-1)/2;
}
}
heap[j]=temp;
}
public:
MinHeap(int sz=defaultSize)
{
maxHeapSize=(defaultSize<sz)?sz:defaultSize;
heap = new T[maxHeapSize];
if(!heap)
{
cout<<"¶Ñ´æ´¢·ÖÅäʧ°Ü"<<endl;
exit(1);
}
currentSize=0;
}
MinHeap(T* ary, int n)
{
maxHeapSize=(defaultSize<n)?n:defaultSize;
heap=new T [maxHeapSize];
if(heap==NULL)
{
cout<<"¶Ñ´æ´¢·ÖÅäʧ°Ü"<<endl;
exit(1);
}
for(int i=0; i<n; i++)
{
heap[i]=ary[i];
}
currentSize = n;
int curPos=(currentSize-2)/2;
while(curPos>=0)
{
SiftDown(curPos,currentSize-1);
curPos--;
}
}
~MinHeap()
{
delete [] heap;
}
bool Insert(const T& x)
{
if(currentSize==maxHeapSize)
{
cout<<"Heap Full"<<endl;
return false;
}
heap[currentSize++]=x;
SiftUp(currentSize-1);
return true;
}
bool Remove(T& x)
{
if(!currentSize)
{
cout<<"Heap empty"<<endl;
return false;
}
x=heap[0];//最小堆,权值小的在上面,对应数组下标也小
heap[0]=heap[currentSize-1];
currentSize--;
SiftDown(0,currentSize-1);
return true;
}
bool IsEmpty()
{
return currentSize==0;
}
void MakeEmpty()
{
currentSize=0;
}
};
template <typename T>
class PriorityQueue: public MinHeap<T>//子类,用父类的构造函数
{
public:
bool EnQueue(const T& elem)
{
return MinHeap<T>::Insert(elem);
}
bool DeQueue(T& elem)
{
return MinHeap<T>::Remove(elem);
}
bool IsEmpty()
{
return MinHeap<T>::IsEmpty();
}
};
struct NodeInfo
{
int from;
int to;
int weight;
int time;//设置时间是为了如果边权相同,先进队列的优先级高
/********************易错*************/
bool operator<=(const NodeInfo& node)
{
return weight<=node.weight;
}
bool operator<(const NodeInfo& node)
{
if(weight==node.weight)
return time<node.time;
else
return weight<node.weight;
}
bool operator>(const NodeInfo& node)
{
if(weight==node.weight)
return time>node.time;
else
return weight>node.weight;
}
bool operator>=(const NodeInfo& node)
{
return weight>=node.weight;
}
};
void Print(int a)//输出函数
{
cout<<a<<" ";
}
class DisjointSet//并查集
{
private:
int *parent;//序号数组
public:
DisjointSet(int n=100)//并查表
{
parent=new int [n];
for(int i=0; i<n; i++)
{
parent[i]=i;
}
}
~DisjointSet()
{
delete [] parent;
}
int Find(int u)
{
//查找
while(parent[u]!=u)
{
u=parent[u];
}
return u;
}
void Merge(int v, int u)//合并
{
parent[u]=v;//将第二个转化为和第一个一样的序号
}
};
void Prim(int **Tlist,int n)
{
int *visit=new int[n];
for(int i=0; i<n; i++)
visit[i]=0;
int **outlist;
outlist=new int*[n];
for(int i=0; i<n; i++)
{
outlist[i]=new int[n];
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
outlist[i][j]=0;
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
Print(outlist[i][j]);
}
cout<<endl;
}
cout<<endl;
visit[0]=1;
NodeInfo iter;
PriorityQueue<NodeInfo> q;
for(int i=0; i<n; i++)
{
if(Tlist[0][i]!=0)
{
iter.from=0;
iter.to=i;
iter.weight=Tlist[0][i];
q.EnQueue(iter);
}
}
int sum=0;
while(!q.IsEmpty())
{
q.DeQueue(iter);
if(visit[iter.to]!=1)//终点没有被标记的话则出队,遍历
/*************************************易错****************************/
{
visit[iter.to]=1;
outlist[iter.from][iter.to]=iter.weight;
outlist[iter.to][iter.from]=iter.weight;
for(int i=0; i<n; i++)
{
NodeInfo m;
if(visit[i]!=1&&Tlist[iter.to][i]>0)//应该是to点是否标记
{
m.from=iter.to;
m.to=i;
m.weight=Tlist[iter.to][i];
q.EnQueue(m);
}
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
Print(outlist[i][j]);
}
cout<<endl;
}
cout<<endl;
sum++;
if(sum==n-1)
break;
}
}
}
void Kruskal(int **Tlist,int n)
{
int **outlist;
outlist=new int*[n];
DisjointSet ds(n);//利用并查表
for(int i=0; i<n; i++)
{
outlist[i]=new int[n];
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
outlist[i][j]=0;
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
Print(outlist[i][j]);
}
cout<<endl;
}
cout<<endl;
NodeInfo iter;
PriorityQueue<NodeInfo> q;
int stime=0;
for(int i=0; i<n; i++) //因为对称矩阵,所以取矩阵的一半
{
for(int j=0; j<i; j++)
{
if(Tlist[j][i]!=0)
{
iter.from=j;
iter.to=i;
iter.weight=Tlist[j][i];
iter.time=stime++;
q.EnQueue(iter);
}
}
}
while(!q.IsEmpty())
{
q.DeQueue(iter);
int u=ds.Find(iter.from);
int v=ds.Find(iter.to);
if(u!=v)
{
ds.Merge(u,v);
outlist[iter.from][iter.to]=iter.weight;
outlist[iter.to][iter.from]=iter.weight;
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
Print(outlist[i][j]);
}
cout<<endl;
}
cout<<endl;
}
}
}
int main()
{
int n;
cin>>n;
int **a;//邻接矩阵
a=new int*[n];
for(int i=0; i<n; i++)
{
a[i]=new int[n];
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
cin>>a[i][j];
}
cout<<"Prim:"<<endl;
Prim(a,n);
cout<<"Kruskal:"<<endl;
Kruskal(a,n);
}