oj解题---Prim和Kruskal最小生成树

题目描述

给出一个矩阵,要求以矩阵方式单步输出最小生成树生成过程。要求先输出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);
}


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值