zoukankan      html  css  js  c++  java
  • 最小生成树--->NYOJ-38 布线问题

    此题是最基础的最小生成树的题目,有两种方法, 一个是prim一个是kruskal算法,前者利用邻接矩阵,后者是利用边集数组

    prim算法的思想是:一个点一个点的找, 先找从第一个点到其他点最小的, 把权值存放到一个lowcost的数组中,然后继续找下一个点,然后更新lowcost数组,注意,这时的lowcost不完全是第二个点到所有点的距离,而是,其他点到最小生成树的距离,然后一步一步的求,知道求完所有点

    kruskal算法的思想是:先把边集数组按照权值进行排序,之后从最小的往上找,这时有个前提,就是不能有环,这样就能保证最大连通量为1,借助father数组

    代码如下:

    方法一(Prim):

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <algorithm>
     4 using namespace std;
     5 const int MAX = 500 + 10;
     6 const int INFINITY = 999999;
     7 int map[MAX][MAX];
     8 int Sum;
     9 int v, e;//v来存点的个数,e来存边的个数 
    10 void mini_span_tree_prim()
    11 {
    12     int lowcost[MAX];
    13     lowcost[1] = 0;//标记已经加到最小生成树中 
    14     for(int i = 2; i <= v; i++)
    15     {
    16         lowcost[i] = map[1][i];
    17     }
    18     for(int i = 2; i <= v; i++)
    19     {
    20         int j = 2;
    21         int index = 1;
    22         int minweight = INFINITY;
    23         while(j <= v)
    24         {//找出最小的边来,并保存其坐标 
    25             if(lowcost[j] != 0 && lowcost[j] < minweight)
    26             {
    27                 minweight = lowcost[j];
    28                 index = j;
    29             }
    30             j++;
    31         }
    32         lowcost[index] = 0;//标记已经加到最小生成树中 
    33         Sum += minweight;
    34         for(j = 2; j <= v; j++)
    35         {//判断没有加到最小生成树中的和比当前权值要小的点 
    36             if(lowcost[j] != 0 && lowcost[j] > map[index][j])
    37             {
    38                 lowcost[j] = map[index][j];
    39             }
    40         }
    41     }
    42 }
    43 int main()
    44 {
    45     //freopen("1.txt", "r", stdin);
    46     int n;
    47     scanf("%d", &n);
    48     while(n--)
    49     {
    50         Sum = 0;
    51         scanf("%d %d", &v, &e);
    52         int t1, t2, t3;
    53         memset(map, 1, sizeof(map));
    54         for(int i = 1; i <= v; i++)
    55         {
    56             map[i][i] = 0;
    57         }
    58         for(int i= 0; i < e; i++)
    59         {
    60             scanf("%d %d %d", &t1, &t2, &t3);
    61             map[t1][t2] = t3;
    62             map[t2][t1] = t3;
    63         }
    64         int mincost = INFINITY;
    65         for(int i = 0; i < v; i++)
    66         {
    67             scanf("%d", &t1);
    68             mincost = min(mincost, t1);
    69         }
    70         mini_span_tree_prim();
    71         printf("%d
    ", Sum + mincost);
    72     }    
    73     return 0;
    74 } 

    方法二(Kruskal):

    #include <stdio.h>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    typedef struct Node{
        int s;
        int e;
        int weight;
    }Node;
    const int MAX = 500 + 10;
    const int INFINITY = 99999999;
    Node arr[MAX * 250];
    int father[MAX];
    int sum;
    int v, edges;
    
    bool cmp(Node a, Node b)
    {
        return a.weight < b.weight;
    }
    
    int find(int f)
    {
        while(father[f] > 0)
            f = father[f];
        return f;
    }
    //生成最小生成树 
    void mini_span_tree_kruskai()
    {
        int n, m;
        int cnt = 0;
        for(int i= 0; i < edges; i++)
        {
            n = find(arr[i].s);
            m = find(arr[i].e);
            if(cnt == v - 1)//优化,如果找到了n-1条边,这时退出就行了 
                break;
            if(n != m)//判断是否构成了环 
            {
                father[m] = n;
                sum += arr[i].weight;
                cnt++;
            }
        }
    }
    
    int main()
    {
        int n;
        scanf("%d", &n);
        while(n--)
        {
            memset(arr, 0, sizeof(arr));
            memset(father, 0, sizeof(father));
            sum = 0;
            scanf("%d %d", &v, &edges);
            for(int i = 0; i < edges; ++i)
            {
                scanf("%d %d %d", &arr[i].s, &arr[i].e, &arr[i].weight);
            }
            int mincost = INFINITY;
            int t;
            for(int i = 1; i <= v; i++)
            {
                scanf("%d", &t);
                mincost = min(mincost, t);
            }
            sort(arr, arr + edges, cmp);//排序 
        //    for(int i = 0; i < edges; i++)
    //            printf("%d %d %d
    ", arr[i].s, arr[i].e, arr[i].weight);
    //        printf("%d
    ", mincost);
            mini_span_tree_kruskai();
            printf("%d
    ", sum + mincost);
            
        }        
        return 0;
    }
  • 相关阅读:
    VS2013使用scanf、gets及字符串函数编译报错error C4996: 'scanf': This function or variable may be unsafe. 原因及解决方案
    关于vs2013与office系列软件一起安装出现bug的情况描述以及解决办法——打开vs2013鼠标不动/动不了
    武汉华师驾校学车笔记_纪实
    vs2013由修改模式改为输入模式。
    解析:求最大公约数的“辗转相除法原理”
    关于scanf与scanf_s的区别,以及用scanf编译出错并且提示找不到可执行文件.exe的解决办法。
    [C编译器]在VS中编译调试C程序
    使用vs编译程序选择新建”空项目“与”win32控制台应用程序“的区别。
    AngularJS+Ionic开发-1.搭建开发环境
    PetaPoco源代码学习--3.Sql类
  • 原文地址:https://www.cnblogs.com/Howe-Young/p/4083810.html
Copyright © 2011-2022 走看看