• 月球美容计划之最小生成树(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;
    }
    



  • 相关阅读:
    IDEA怎么自动生成serialVersionUID
    使用gcc的-l参数的时候,怎么查找函数所在库的位置
    有一个10 G 的文件,你只有有一个 2 G 的内存,找出重复最多的数字
    gdb调试使用教程
    使用autoscan自动生成makefile文件
    如何查看yum命令安装的软件的安装目录
    手机QQ邮箱app有未读邮件,图标右上角没有红色小圆点的解决方案
    谷歌google帐号(邮箱)注册时,提示此电话号码无法用于验证
    Notepad++编写的shell脚本在linux下无法执行的解决方法
    linux如何配置普通用户(非root用户)的sudo权限
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10505106.html
Copyright © 2020-2023  润新知