数据结构 笔记:最小生成树(prim)

运营商的挑战

-在下图标出的城市间架设一条通信线路

要求:

·任意两个城市间都能够通信

·将架设成本呢将至最低

 

如何在图中选择n-1条边使得n个顶点间两两可达,并且这n-1条边的权值之和最小

最小生成树

-仅使用图中的n-1条边连接图中的n个顶点

-不能使用产生回路的边

-个边上的权值的总和达到最小

最小生成树算法步骤

-选择某一顶点V0作为起始顶点,是的T={V0},F={V1,V2,...Vn},E={ }

-每次选择一条边,这条边是所有(u,v)中权值最小的边,且u属于T,v属于F

-修改T,F,E:

T = T + {v} ,F = F - {v}, E = E + {(u,v)}

-当F != NULL是,切(u,v)存在,转2;否则,结束

 最小生成树算法的原材料

类型变量用途
Array<bool>mark标记顶点所属的集合(T or F)
Array<E>cost记录T集合到F集合中顶点的最小权值
Array<int>adjVex记录cost中权值的对应顶点
Queue<Edge>ret记录最小生成树中的边

注意事项

-最小生成树仅针对无向图有意义

-必须判断图对象是否能够看做无向图

图类型(Graph)中的新增成员函数

-virtual bool isAdjacent (int i,int j) = 0;

-bool assUndirected();

·判断当前的有向图是否能够看做无向图

    bool isAdjacent(int i ,int j)
    {
        return (0 <= i) && ( i < vCount()) && ( 0 <= j) && (j < vCount()) && (m_list.get(i)->edge.find(Edge<E>(i,j)) >=0);
    }
    bool asUndirected()
    {
        bool ret = true;

        for(int i = 0;i<vCount() ; i++)
        {
            for(int j = 0;j<vCount();j++)
            {
                if(isAdjacent(i,j))
                {
                    ret = ret && isAdjacent(j,i) && (getEdge(i,j) == getEdge(j,i));
                }
            }
        }
        return ret;
    }

    SharedPointer <Array <Edge <E> >> prim( const E& LIMIT,const bool MINIMUM = true)
    {
        LinkQueue<Edge<E>> ret;

        if(asUndirected())
        {
            DynamicArray<int> adjVex(vCount());
            DynamicArray<bool> mark(vCount());
            DynamicArray<E> cost(vCount());
            SharedPointer<Array<int>> aj = NULL;
            bool end = false;
            int v = 0;

            for(int i = 0;i<vCount() ; i++)
            {
                adjVex[i] = -1;
                mark[i] = false;
                cost[i] = LIMIT;
            }

            mark[v] = true;

            aj = getAdjacent(v);

            for(int j = 0;j < aj->length();j++)
            {
                cost[(*aj)[j]] = getEdge(v,(*aj)[j]);
                adjVex[(*aj)[j]] = v;
            }

            for(int i = 0;(i<vCount()) && !end;i++)
            {
                E m = LIMIT;
                int k = -1;

                for(int j = 0;j<vCount();j++)
                {
                    if( !mark[j] && (MINIMUM ?(cost[j] < m) :(cost[j] > m)))
                    {
                        m = cost[j];
                        k = j;
                    }
                }

                end = (k == -1);

                if(!end)
                {
                    ret.add(Edge<E>(adjVex[k],k,getEdge(adjVex[k],k)));

                    mark[k] = true;

                    aj = getAdjacent(k);

                    for(int j = 0;j<aj->length();j++)
                    {
                        if(!mark[(*aj)[j]] && (MINIMUM ? (getEdge(k,(*aj)[j]) < cost[(*aj)[j]]):(getEdge(k,(*aj)[j]) > cost[(*aj)[j]])))
                        {
                            cost[(*aj)[j]] = getEdge(k,(*aj)[j]);
                            adjVex[(*aj)[j]] = k;
                        }
                    }
                }
            }
        }
        else
        {
            //抛出异常
        }

        if(ret.length() != (vCount() -1))
        {
            //抛出异常
        }
        return toArray(ret);
    }

总结:

-最小生成树使得顶点间的连通代价最小

-Prim算法通过顶点的动态标记寻找最小生成树

-Prim算法的关键是集合概念的援用(T 集合,F 集合)

-利用Prim算法的思想也能寻找图的“最大生成树”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值