最小生成树---Prim

Prim算法的特点是集合E中的边总是形成单棵树,树从任意根节点s开始形成,
并逐渐生成,直至该树覆盖了V中的所有顶点。

设图G =(V,E),其生成树的顶点集合为U。
①.把v0放入U
②.在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树
③.把②找到的边的v加入U集合。如果U集合已有n个元素,则结束,否则继续执行②

Challenge: Find the min weight edge with exactly one endpoint in T
Lazy solution: Maintain a PQ of edges with (at least) one endpoint in T
(1)key=edge; priority=weight of edge
(2)delete-min to determine next edge e=(u,v) to add to T
(3)disregard if both endpoints u and v are in T
(4)otherwise, let u be the vertex not in T
    add to PQ any edge incident to u(assue other endpoint not in T)
    add u to T


#include <stdio.h>
#include <string.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 PrimMST
{
public:
        PrimMST(EdgeWeightedGraph *g, int s);
        ~PrimMST();
        queue<Edge *> edges() { return mst; }
        double getWeight() { return weight; }

private:
        void visit(EdgeWeightedGraph *g, int v);

private:
        bool *marked;     //true:visited, false:unvisited
        priority_queue<Edge *, vector<Edge *>, EdgeCmp> pq;
        double weight;    //weight of mst
        queue<Edge *> mst;//edges in mst
};

PrimMST::PrimMST(EdgeWeightedGraph *g, int s)
{
        weight = 0;
        int v = g->getV();
        marked = new bool[v];
        memset(marked, false, v);

        visit(g, s);
        while(!pq.empty())
        {
                Edge *e = pq.top();
                          pq.pop();
                int u = e->either();
                int v = e->other(u);

                if (marked[u] && marked[v])
                        continue;

                mst.push(e);
                weight += e->getWeight();

                if (!marked[u])
                        visit(g, u);
                if (!marked[v])
                        visit(g, v);
        }
}

PrimMST::~PrimMST()
{
        if (NULL != marked)
        {
                delete []marked;
                marked = NULL;
        }
}

// add all edges e incident to v onto pq if other endpoint has not yet been visited
void PrimMST::visit(EdgeWeightedGraph *g, int v)
{
        marked[v] = true;
        list<Edge *> ls = g->getAdj(v);
        for (list<Edge *>::iterator it = ls.begin(); it != ls.end(); ++it)
                if (!marked[(*it)->other(v)])
                        pq.push(*it);
}

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);
        PrimMST pmst(&graph, 0);

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

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

        return 0;
}

0 -- 7 :    0.160
1 -- 7 :    0.190
0 -- 2 :    0.260
2 -- 3 :    0.170
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、付费专栏及课程。

余额充值