zoukankan      html  css  js  c++  java
  • 贪心算法训练(三)——最小生成树

    • 问题描述
      • 求一个连通无向图的最小生成树的代价(图边权值为正整数)
    • 输入
      • 第一行是一个整数 N (1 <= N <= 20) ,表示有多少个图需要计算,以下有 N 个图,第 i 图的第一行是一个整数 M (1 <= M <= 50) ,表示图的顶点数,第 i 图的第 2 行至 1+M 行为一个 M*M 的二维矩阵,其元素 ai,j 表示图的 i 顶点和 j 顶点的连接情况,如果 ai ,j = 0,表示 i 顶点和 j 顶点不相连,如果 ai ,j > 0,表示 i 顶点和 j 顶点的连接权值
    • 输出
      • 每个用例,用一行输出对应图的最小生成树的代价
    • 样例输入
          1
          6
          0 6 1 5 0 0
          6 0 5 0 3 0 
          1 5 0 5 6 4
          5 0 5 0 0 2
          0 3 6 0 0 6
          0 0 4 2 6 0
    
    • 样例输出
      15
    • Kruskal 算法
      • 对于一个 N*N 矩阵,先构造 N 个没有连接的顶点,按边权值大小从小到大选择顶点,连接不同的生成树,一条边连接 2 个顶点,那么这两个顶点就在同一颗树上,要保证每次连接的树都是不同的,直到只剩下一颗树为止,假如现有一条边连接了 A,B 两个顶点,另一条连接了 B,C 顶点,那么 A,B,C在同一颗树上, A,C 不能再被边连接,同样, C 顶点连接的其他顶点也不能和 A 相连,那么如何做出这样的判断呢?
    • 算法设计
      • 对边权值从小到大排序,采用链式结构,每个节点存储边连接的左右端点
      • 判断边的加入是否构成了环,如果构成了环,那么这条边的加入是不合理的
    • 代码
        #include<iostream>
        
        using namespace std;
        
        struct Node
        {
            int l;
            int r;
            int len;
            Node *next;
        };
        
        void insert(Node *&head,Node *p);
        
        int main()
        {
            Node *head,*p;
            int n,m,x,temp;
            int *a;
            int i,j;
            int sum;
            cin>>n;
            while(n--)
            {
                sum = 0;
                cin>>m;
                a = new int[m+1];
                for (i = 1; i <= m; i++)
                {
                    a[i] = i;               //各端点自为一组
                }
                head = new Node;
                p = head;
                p->next = NULL;
                for (i = 1; i <= m; i++)
                    for (j = 1; j <= m; j++)
                    {
                        cin>>x;
                        if (i > j && x != 0)   //对称矩阵
                        {
                            p=new Node;
                            p->l = i;
                            p->r = j;
                            p->len = x;
                            p->next = NULL;
                            insert(head,p);
                        }
                    }
                p = head->next;
                while (p)
                {
                    if (a[p->l] != a[p->r])  //判断是否为同一组
                    {
                        sum += p->len;
                        temp = a[p->l];       //记录左端点
                        for(i = 1; i <= m; i++)
                            if (a[i] == temp)   //找到原左端点的值
                            {
                                a[i] = a[p->r]; //将左端点的值改为和右端点一致
                            }
                    }
                    p = p->next;
                }
                cout<<sum<<endl;
            }
            return 0;
        }
        
        void insert(Node *&head,Node *p)
        {
            Node *q = head;
            while(q->next && q->next->len <= p->len)  //从头结点开始,大的放后面
            {
                q = q->next;
            }
            p->next = q->next;
            q->next = p;
        }
    
  • 相关阅读:
    CentOS 6.5 下源码搭建LAMP环境
    CentOS 6.5 下MySql主从、主主配置
    js基础梳理内存空间
    js基础梳理如何理解作用域和作用域链?
    js基础梳理究竟什么是变量对象,什么是活动对象?
    js基础梳理究竟什么是执行上下文栈(执行栈),执行上下文(可执行代码)?
    python作用域解析
    expect简单自动交互用于密码、命令输入
    使用pyinstaller打包多个py文件为一个EXE文件
    python*args和**kwargs作用和区别
  • 原文地址:https://www.cnblogs.com/NikkiNikita/p/9458530.html
Copyright © 2011-2022 走看看