最小生成树-Kruskal

本文介绍了一种使用Kruskal算法解决最小生成树问题的方法,并通过实例展示了算法的应用。其中包括构建边权重图、使用优先队列进行排序、并查集判断是否存在环等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.首先将G的n个顶点看成n个孤立的连通分支(n个孤立点)并将所有的边按权从小大排序
2.裁取权值最小的边,如果加入此边后存在圈则这条边不加入,重复这个操作,直到加入n-1条边

#include <stdio.h>
#include <iostream>
#include <list>
#include <vector>
#include <queue>
#include <string>

using std::list;
using std::vector;
using std::queue;
using std::priority_queue;
using std::string;
using std::cout;
using std::endl;

class Edge
{
public:
        Edge(int u, int v, double w)
        {
                if (u >= 0 && v >= 0)
                {
                        this->u = u;
                        this->v = v;
                        this->weight = w;
                }
        }
        double getWeight() { return weight; }
        int either() { return u; }
        int other(int p)
        {
                if (p == u)
                        return v;
                else if (p == v)
                        return u;
        }

        string toString()
        {
                string str;
                char result[64] = "";
                sprintf(result, "%d -- %d : %8.3f\n", u, v, weight);
                str = result;
                return str;
        }

private:
        int u;
        int v;
        double weight;
};

class EdgeCmp
{
public:
        bool operator() (Edge *p, Edge *q)
        {
                return p->getWeight() > q->getWeight();
        }
};

class EdgeWeightedGraph
{
public:
        EdgeWeightedGraph(int nVertex, int nEdge, int arr[][2], double weight[]);
        ~EdgeWeightedGraph();
        int getV() { return V; }
        list<Edge *> edges();
        list<Edge *> getAdj(int v);

private:
        int V;
        int E;
        list<Edge *> *adj;
};

EdgeWeightedGraph::EdgeWeightedGraph(int nVertex, int nEdge, int arr[][2], double weight[])
{
        V = nVertex;
        E = nEdge;
        adj = new list<Edge *>[nVertex];

        for (int i = 0; i < E; ++i)
        {
                Edge *e = new Edge(arr[i][0], arr[i][1], weight[i]);
                adj[arr[i][0]].push_back(e);
                adj[arr[i][1]].push_back(e);
        }
}

EdgeWeightedGraph::~EdgeWeightedGraph()
{
        list<Edge *> ls = edges();
        for (list<Edge *>::iterator it = ls.begin(); it != ls.end(); ++it)
        {
                delete *it;
                *it = NULL;
        }

        delete []adj;
        adj = NULL;
}

list<Edge *> EdgeWeightedGraph::getAdj(int v)
{
        if (v >= 0 && v < V)
                return adj[v];
}

list<Edge *> EdgeWeightedGraph::edges()
{
        list<Edge *> ls;
        for (int i = 0; i < V; ++i)
        {
                int selfLoops = 0;
                list<Edge *> tmpList = getAdj(i);
                for (list<Edge *>::iterator it = tmpList.begin(); it != tmpList.end(); ++it)
                {
                        if ((*it)->other(i) > i)
                                ls.push_back(*it);
                        else if ((*it)->other(i) == i)//only add one copy of each self loop
                        {
                                if (0 == selfLoops%2)
                                        ls.push_back(*it);
                                ++selfLoops;
                        }
                }
        }

        return ls;
}

class UF
{
public:
        UF(int n);
        ~UF();
        int find(int p);
        bool connected(int p, int q);
        void unite(int p, int q);
private:
        int *id;     // id[i]=parent of i
        int *rank;   // rank[i]=rank of subtree rooted at i
        int num;     // number of vertex
        int count;   // number of components
};

UF::UF(int n)
{
        if (n > 0)
        {
                count = n;
                num = n;
                id = new int[n];
                rank = new int[n];
                for (int i = 0; i < n; ++i)
                {
                        id[i] = i;
                        rank[i] = 0;
                }
        }
}

UF::~UF()
{
        if (NULL != id)
        {
                delete []id;
                id = NULL;
        }

        if (NULL != rank)
        {
                delete []rank;
                rank = NULL;
        }
}

int UF::find(int p)
{
        if (p >=0 && p <num)
        {
                while (p != id[p])
                        p = id[p];
        }

        return p;
}

bool UF::connected(int p, int q)
{
        return find(p) == find(q);
}

void UF::unite(int p, int q)
{
        int i = find(p);
        int j = find(q);

        if (i == j)
                return ;

        // make root of smaller rank point to root of larger rank
        if (rank[i] < rank[j])
                id[i] = j;
        else if (rank[i] > rank[j])
                id[j] = i;
        else
        {
                id[i] = j;
                ++rank[j];
        }

        --count;
}

class KruskalMST
{
public:
        KruskalMST(EdgeWeightedGraph *g);
        queue<Edge *> edges() { return mst; }
        double getWeight() { return weight; }

private:
        double weight;    //weight of mst
        queue<Edge *> mst;//edges in mst
};

KruskalMST::KruskalMST(EdgeWeightedGraph *g)
{
        weight = 0;
        priority_queue<Edge *, vector<Edge *>, EdgeCmp> pq;
        list<Edge *> ls = g->edges();
        for (list<Edge *>::iterator it = ls.begin(); it != ls.end(); ++it)
                pq.push(*it);

        int v = g->getV();
        UF uf(v);
        while(!pq.empty() && mst.size() < (v-1))
        {
                Edge *e = pq.top();
                int u = e->either();
                int v = e->other(u);
                if (!uf.connected(u, v))
                {
                        uf.unite(u, v);
                        mst.push(e);
                        weight += e->getWeight();
                }
                pq.pop();
        }

}

int main()
{
        int arr[][2] = { {0, 7}, {2, 3}, {1, 7}, {0, 2},
                         {5, 7}, {1, 3}, {1, 5}, {2, 7},
                         {4, 5}, {1, 2}, {4, 7}, {0, 4},
                         {6, 2}, {3, 6}, {6, 0}, {6, 4}
                        };
        double wgt[] = {0.16, 0.17, 0.19, 0.26, 0.28, 0.29, 0.32, 0.34,
                        0.35, 0.36, 0.37, 0.38, 0.40, 0.52, 0.58, 0.93};

        EdgeWeightedGraph graph(8, 16, arr, wgt);
        KruskalMST kmst(&graph);

        queue<Edge *> edge = kmst.edges();
        while (!edge.empty())
        {
                cout << edge.front()->toString();
                edge.pop();
        }

        cout << "weight: " << kmst.getWeight() << endl;

        return 0;
}

0 -- 7 :    0.160
2 -- 3 :    0.170
1 -- 7 :    0.190
0 -- 2 :    0.260
5 -- 7 :    0.280
4 -- 5 :    0.350
6 -- 2 :    0.400
weight: 1.81

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值