关闭

最小生成树

1042人阅读 评论(0) 收藏 举报
分类:
#include<iostream>
#include<stdlib.h>//产生随机数组用
#include<time.h> //同上

using namespace std;


class MyArc
{
public:
    int m_beginVex;
    int m_endVex;
    int m_weight;
    MyArc(int beginVex,int endVex,int weight);
    MyArc(){}
    bool operator < (const MyArc& arc)
    {
        return m_weight<arc.m_weight;
    }
    bool operator == (const MyArc& arc)
    {
        return m_weight==arc.m_weight;
    }
    bool operator > (const MyArc& arc)
    {
        return m_weight>arc.m_weight;
    }
};

MyArc::MyArc(int beginVex,int endVex,int weight):m_beginVex(beginVex),m_endVex(endVex),m_weight(weight)
{

}

class Graph
{
public:
    int m_vexnum;//顶点数
    int m_arcnum;//弧数目
    int *m_pmatrix;
public:
    ~Graph();
    Graph(int vexnum);
    Graph(int vexnum,int *pmatrix);
    void insert(MyArc arc);//按权值大小排序插入
    bool bound(int x);   //判断顶点x是否已与其它顶点连通

};

//构造函数
Graph::Graph(int vexnum)
{
    m_pmatrix=new int[vexnum*vexnum];
    m_vexnum=vexnum;
    m_arcnum=0;
    for(int i=0;i<vexnum*vexnum;++i)
    {
        m_pmatrix[i]=0; //初始化邻接矩阵
    }


}

//构造函数
Graph::Graph(int vexnum,int *pmatrix)
{
    m_vexnum=vexnum;
    // m_arcnum=arcnum;
    m_pmatrix=new int[m_vexnum*m_vexnum];
    for(int i=0;i<m_vexnum*m_vexnum;++i)
    {
        m_pmatrix[i]=pmatrix[i];
    }
}

//测试 顶点x是否已与其他点连通
bool Graph::bound(int x)
{
    for(int i=0;i<m_vexnum;++i) if(m_pmatrix[x+i*m_vexnum]!=0) return true;
    return false;
}

//在邻接表中连通 arc表示的边,并且设置权
void Graph::insert(MyArc arc)
{
    m_pmatrix[arc.m_beginVex*m_vexnum+arc.m_endVex]=arc.m_weight;
    m_pmatrix[arc.m_endVex*m_vexnum+arc.m_beginVex]=arc.m_weight;
    ++m_arcnum;
}
//析构
Graph::~Graph()
{
    delete[] m_pmatrix;
    m_pmatrix = NULL;
}

class MyQueues
{
public:
    list<MyArc> m_list;
    MyQueues(){}
    void insert(const MyArc& arc);//边按权值插入队列中合适位置,
    void InsertGraph(const Graph &graph);//将图的连通分量插入队列
    MyArc pop();
};
//边出队
MyArc MyQueues::pop()
{
    MyArc arc=m_list.front();
    m_list.pop_front();
    return arc;
}
//边按权值插入队列中合适位置,
void MyQueues::insert(const MyArc& arc)
{
    list<MyArc>::iterator pos=m_list.begin();
    while(pos!=m_list.end())
    {
        if(*pos>arc) break;
        else
            ++pos;
    }
    m_list.insert(pos,arc);
}
//将图的连通分量插入队列
void MyQueues::InsertGraph(const Graph &graph)
{
    for(int i=0;i<graph.m_vexnum;++i)
    {
        for(int j=i+1;j<graph.m_vexnum;++j)//上三角矩阵的联通分量
              {
                if(graph.m_pmatrix[i*graph.m_vexnum+j])
                    insert(MyArc(i,j,graph.m_pmatrix[i*graph.m_vexnum+j]));
              }
    }
}
//用随机数组初始化matrix数组并且打印
void SetMatrix(int vexnum,int *pmatrix)
{
    srand((unsigned)time(NULL));
    for(int i=0;i<vexnum;++i)//产生随机权值矩阵
    {
        for(int j=i;j<vexnum;++j)
        {
              if(j==i)
              {
                  pmatrix[i*vexnum+j]=0;
                  continue;
              }
              int rnum=rand();
              rnum%=99;
              rnum++;//产生1~99的随机整数作为边的权值
              pmatrix[i*vexnum+j]=rnum;//先填写上三角矩阵
              pmatrix[j*vexnum+i]=rnum;//后填写下三角矩阵
        }
    }
    cout<<"***随机产生的各边权值矩阵 [顶点数为 "<<vexnum<<"] ****\n";
  for(int i=0;i<vexnum;++i)//输出随机权值矩阵
    {
        for(int j=0;j<vexnum;++j)
        {
              cout<<pmatrix[i*vexnum+j]<<"\t";
        }
        cout<<endl;
    }

}


//判断连通边arc后 图graph 是否存在回路
bool IsCycle(Graph& graph, MyArc& arc)
{
    list<int> mylist;
    mylist.push_back(arc.m_beginVex);
    int *ps=new int[graph.m_vexnum];
    for(int i=0;i<graph.m_vexnum;++i)
        ps[i]=0;
    while(!mylist.empty())
    {
        int x=mylist.front();
        ps[x]=1;
        mylist.pop_front();
        for(int i=0;i<graph.m_vexnum;++i)
        {
              if(graph.m_pmatrix[i+x*graph.m_vexnum]!=0)
              {
                  if(i==arc.m_endVex) return true;
                  if(ps[i]!=1) mylist.push_back(i);
              }
        }
    }
    delete[] ps;
    return false;//遍历完成没有环
}

//克鲁斯卡尔算法
void kruskal(const Graph& graph,Graph& smtree)
{
    MyQueues arcqueues;//保存从小到大排列的边
    arcqueues.InsertGraph(graph);
    MyArc myarc;//Arc表示边的类型
    int arcnum=0; //边的个数
    while(arcnum<graph.m_vexnum-1)//此处的含义为边的数目正好为顶点数目减一,注意与prim算法表达式相同但是含义不同
    {
        myarc=arcqueues.pop();
        if(!IsCycle(smtree,myarc))
        {
              smtree.insert(myarc);
              ++arcnum;
        }
    }
}

//输出最小生成树
void SmallestTreeOutput(const Graph& smtree)
{
    cout<<"最小生成树:"<<endl;
    for(int i=0;i<smtree.m_vexnum;++i)//输出最小树
        for(int j=i+1;j<smtree.m_vexnum;++j)
              if(smtree.m_pmatrix[i*smtree.m_vexnum+j])
                  cout<<'('<<i<<','<<j<<','<<smtree.m_pmatrix[i*smtree.m_vexnum+j]<<')'<<endl;
}


/*
主函数
*/

int main()
{
    int i;
    cout<<"请输入顶点数目:";
    cin>>i;
    int vex=i;
    int *matrix=new int[vex*vex];
    cout<<endl;
    SetMatrix(vex,matrix);
    Graph graph(vex,matrix),smtree(vex);
    kruskal(graph,smtree);
    SmallestTreeOutput(smtree);
    delete []matrix;
}






 

0
0
查看评论

最小生成树计数-Kruskal+Matrix_Tree定理

/* *算法引入: *给定一个含有N个结点M条边的无向图,求它最小生成树的个数t(G); * *算法思想: *抛开“最小”的限制不看,如果只要求求出所有生成树的个数,是可以利用Matrix-Tree定理解决的; *Matrix-Tree定理此定理利用图的Kirchhoff矩阵,可以在O(...
  • Jarily
  • Jarily
  • 2013-05-08 20:55
  • 5852

贪心算法——Prim最小生成树

1、首先介绍一下什么是贪心算法: 贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。ps:不懂得话可以百度百科,仔细了解。 2、prim算法的原理: 从连通网N={V,E}中的某一顶点U0出发,选择与...
  • baidu_28944591
  • baidu_28944591
  • 2016-06-26 16:50
  • 1760

最小生成树总结

一.最小生成树问题 给定一张图,图中有许多的节点还有许多长度不同的边将这些点点相互连接,找出连接所有点的最短方式就是最小生成树,可以证明,这样一种最小的情况是不会出现环的,由于所有的无环图都可以看做树,所以成为最小生成树。 二.kruskal算法 顶层思想是分治,选择策略是贪心,实现方法如下:...
  • u013555159
  • u013555159
  • 2016-05-07 12:13
  • 844

判断最小生成树的唯一性

先用kruskal算法算出最小生成树,并把最小生成树的边记录下来。然后依次枚举删除边,用其他的边再次使用kruskal算法算出最小生成树。如果算出的代价和原来的相同,则不唯一,否则唯一。另外当我们删除一条边之后,可能根本构不成一颗生成树,要判断一下。 代码如下: #include #include...
  • ECNU_LZJ
  • ECNU_LZJ
  • 2016-12-13 19:38
  • 1559

最小生成树(prim算法与kruskal算法)(模板)

th写的总结,很不错,转载一下:点击打开链接   首先说一下什么是树:     1、只含一个根节点     2、任意两个节点之间只能有一条或者没有线相连    ...
  • zwj1452267376
  • zwj1452267376
  • 2015-08-13 08:54
  • 1500

比较好的题目“典型的最小生成树”

Watering Hole My Tags   (Edit)   Source : USACO 2008 Open   Time limit ...
  • struggle_mind
  • struggle_mind
  • 2014-05-07 21:33
  • 1038

hdu 1233 (最小生成树 简单例题)

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 39416  ...
  • qq_33406883
  • qq_33406883
  • 2016-07-23 15:10
  • 1180

最小生成树(贪心算法)

最小生成树问题——连接n个针脚,可以使用n-1根连线,每个连线连接两个针脚,使得所使用的连线长度最短     抽象为图问题,一个连通无向图G = (V, E),V是针脚的集合,E是针脚之间的可能连接,且对于每条边都有权重w(u, v),希望找到一个无环子集,T属于E,权重之和最...
  • huangwwu11
  • huangwwu11
  • 2015-04-15 23:38
  • 538

Bzoj2561:最小生成树:网络流,最小割

题目链接:最小生成树 发现如果这条边可能出现在最大生成树上的话,那么可以代替这条边的所有边都不连通,换句话说这条边是连接u,v必不可少的 于是我们把所有权值大于L的边建成一张边权去为1的图对U,V跑最小割即可知道最少删去多少条边 最小生成树同理QAQ #include #include #inclu...
  • qq_34025203
  • qq_34025203
  • 2016-05-03 21:07
  • 262

poj1287 Networking 最小生成树模板题。prim+kruskal算法AC

You are assigned to design network connections between certain points in a wide area. You are given a set of points in the area, and a set of possible...
  • Lionel_D
  • Lionel_D
  • 2015-03-26 15:09
  • 890
    公众号,github
    公众号:     老王和他的IT界朋友们
    欢迎投稿:  shiter@live.cn
    QQ交流群:  593683975
    加群问题:抛硬币正面上的期望?

    我们想用一段音乐,几张图片,
    些许文字绘制的IT圈心路历程,
    为攻城狮,为程序员带来更多的人文关怀。

    投稿原创文章有稿费,杂志等福利!!!



    github:  https://github.com/wynshiter
    个人资料
    • 访问:1325387次
    • 积分:14451
    • 等级:
    • 排名:第997名
    • 原创:191篇
    • 转载:51篇
    • 译文:74篇
    • 评论:712条
    博客专栏
    百度统计
    微信公众号
      微信公众号
      老王和他的IT界朋友们