• 月球美容计划之最小生成树(MST)


    寒假学的两个算法。普里姆,克鲁斯卡尔最终弄明确了,能够发总结了

    先说说普里姆。它的本质就是贪心,先从随意一个点開始,找到最短边,然后不断更新更新len数组。然后再选取最短边并标记经过的点,直到全部的点被标记,或者说已经选好了n-1条边。

    拿SDUTOJ2144为例,代码例如以下,可做模板

    #include <stdio.h>
    #include <string.h>
    #define INF 1000000
    
    //最小生成树
    //普里姆
    
    int G[200][200];
    int len[200];
    bool vis[200];
    
    int prm (int n)
    {
        int i,k,ans = 0;
        memset (vis,0,sizeof(vis));
    
        for (i = 2;i <= n;i++)//初始化
            len[i] = G[1][i];
        vis[1] = 1;
        for (i = 1;i < n;i++) //循环n - 1次
        {                     //由于n个顶点的MST一定是n-1条边
            int imin = INF,xb;
            for (k = 1;k <= n;k++)
                if (!vis[k] && imin > len[k])
                {
                    imin = len[k];
                    xb = k;
                }
    
            if (imin == INF)  //没有找到最小值。说明图不连通
                return -1;
    
            vis[xb] = 1;
            ans += imin;
    
            for (k = 1;k <= n;k++)
                if (!vis[k] && len[k] > G[xb][k])
                    len[k] = G[xb][k];
        }
    
        return ans;
    }
    
    int main()
    {
        int n,m;
    
        while (~scanf ("%d%d",&n,&m))
        {
            int i,k;
    
            for (i = 1;i <= n;i++)
                for (k = 1;k <= n;k++)
                    if (i != k)
                        G[i][k] = INF;
                    else
                        G[i][k] = 0;
    
            for (i = 0;i < m;i++)
            {
                int a,b,c;
                scanf ("%d%d%d",&a,&b,&c);
                if (G[a][b] > c)       //假设有边多次录入,选权最小的那个
                    G[a][b] = G[b][a] = c;
            }
    
            int ans = prm(n);
    
            printf ("%d
    ",ans);
        }
        return 0;
    }
    

    克鲁斯卡尔,一个排序一个并查集仅仅是表面。实质还是贪心,仅仅只是普里斯是任选一个点选最短路,而克鲁斯卡尔是看全局,全体边排序,当然,由于排序。导致时间复杂度不easy降下来。


    相同的题,代码例如以下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define INF 1000000
    
    //最小生成树
    //克鲁斯卡尔
    
    int vis[200];
    struct eg
    {
        int v,u,w;
    }e[100000];
    
    int cmp (const void *a,const void *b)
    {
        struct eg *ta = (struct eg *)a;
        struct eg *tb = (struct eg *)b;
    
        return ta->w - tb->w;
    }
    
    int fin (int a)
    {
        int r = a;
    
        while (vis[r] != r)
            r = vis[r];
        int k;
        while (vis[a] != a)
        {
            k = vis[a];
            vis[a] = r;
            a = vis[k];
        }
        return r;
    }
    
    int add (int a,int b)
    {
        vis[fin(a)] = fin (b);
        return 0;
    }
    
    int kls(int n,int m)
    {
        int i;
        int ans = 0;
    
        for (i = 0;i <=n;i++)
            vis[i] = i;
    
        for (i = 0;i < m;i++)
        {
            if (fin(e[i].u) != fin(e[i].v))
            {
                add (e[i].u,e[i].v);
                ans += e[i].w;
            }
        }
    
        return ans;
    }
    
    int main()
    {
        int n,m;
    
        while (~scanf ("%d%d",&n,&m))
        {
            int i,k;
            for (i = 0;i < m;i++)
            {
                int a,b,c;
                scanf ("%d%d%d",&a,&b,&c);
    
                e[i].u = a;
                e[i].v = b;
                e[i].w = c;
            }
            qsort(e,m,sizeof(e[0]),cmp);
            int ans = kls(n,m);
    
            printf ("%d
    ",ans);
        }
        return 0;
    }
    



  • 相关阅读:
    swiper 增加一个鼠标移入分页器的小点后就切换展示图片
    css中的单冒号和双冒号 以及 伪类和伪元素
    pointer-events: none;元素永远不会成为鼠标事件的target
    jQuery off() 方法
    jQuery方法汇总
    vue 数组修改 页面无法刷新
    mysql error Code 1441:datetime function: datetime field overflow
    生命的意义
    删除镜像或容器
    nginx Redis 不能访问问题
  • 原文地址:https://www.cnblogs.com/mthoutai/p/6735094.html
Copyright © 2020-2023  润新知