zoukankan      html  css  js  c++  java
  • POJ2349二分+并查集,类似最小树的贪心

    题意:
          给你n个点,你的任务是构建一颗通讯树,然后给你一个s表示可以选出来s个点两两通讯不花钱,就是费用是0,其他的费用就是两点的距离,有个要求就是其他的费用中最大的那个最小。


    思路:
         方法比较多,题目也不难,但是容易有一个误区就是很多人认为这个题目是在求最小生成树,我不是这么想的(虽然这个题目可以用最小树的算法过,但是我的感觉是他和最小树是相同的代码,不同的思想),因为最小树毕竟是求全局和的最小,而这个题目是求全局中最大的最小,这样首先容易让人想到的就是直接二分,二分距离,然后去用并查集或者是搜索啥的去判断联通快个数啥的,这样是很容易理解的,我试了下,可以ac,但是回来说最小树,这个题目直接用最小树的算法也可以ac,但是思路和最小树的想法没啥关系,在克鲁斯卡尔里,大体思想是 排序后 如果当前这两个连通块没有连接,那么就直接用最小的代价,也就是当前的花费去连接,因为早晚都得连接,不如趁现在最省的时候,就这样贪心到最后就是最下生成树,但是这个题目的想法却是,既然你是求最大的最小,那么我们排序后就一个一个往里面添加,知道满足要求的时候就直接停止就行了。和最小树的写法没啥区别,但是理论依据不同,这个要清楚。还有就是我用两种方法写了下(还可以有更多方法,什么二分+搜索啥的都行),其中一个是类似最小树那样,另一个是二分+并查集,我的二分里面没啥大优化,如果像更快的话,二分的时候可以直接二分任意两点所有的距离,就是说答案肯定是任意两点距离中的一个,这样可以缩短二分范围。。。。。




    二分+并查集
    #include<math.h>
    #include<stdio.h>
    #include<algorithm>


    #define eps 0.000001


    using namespace std;


    typedef struct
    {
        int x ,y;
    }NODE;


    typedef struct
    {
        int a ,b;
        double c;
    }EDGE;


    NODE node[500+5];
    EDGE edge[500*500/2+10];
    int mer[500+5] ,n ,m;


    bool camp(EDGE a ,EDGE b)
    {
        return a.c < b.c;
    }


    int finds(int x)
    {
        return x == mer[x] ? x : mer[x] = finds(mer[x]);
    }


    bool ok(int nowid ,double now)
    {
        for(int i = 1 ;i <= n ;i ++)
        mer[i] = i;
        int s = 0;
        for(int i = 1 ;i <= nowid ;i ++)
        {
            if(edge[i].c > now) break;
            int x = finds(edge[i].a);
            int y = finds(edge[i].b);
            if(x == y) continue;
            s ++;
            mer[x] = y;
            if(s + m >= n) return 1;
        }
        return 0;


    }


    double Search2(int nowid)
    {
        double low = 0 ,up = edge[nowid].c;
        double mid;
        while(up - low >= eps)
        {
            mid = (low + up) / 2;
            if(ok(nowid ,mid))
            up = mid - eps;
            else low = mid + eps;
        }
        return low;
    }


    double GetDis(NODE a ,NODE b)
    {
        double x = (a.x - b.x) * (a.x - b.x);
        double y = (a.y - b.y) * (a.y - b.y);
        return sqrt(x + y);
    }


    int main ()
    {
        int t ,i ,j ,nowid;
        scanf("%d" ,&t);
        while(t--)
        {
            scanf("%d %d" ,&m ,&n);
            nowid = 0;
            for(i = 1 ;i <= n ;i ++)
            {
                scanf("%d %d" ,&node[i].x ,&node[i].y);
                for(j = 1 ;j < i ;j ++)
                {
                    ++nowid;
                    edge[nowid].a = i;
                    edge[nowid].b = j;
                    edge[nowid].c = GetDis(node[i] ,node[j]);
                }
            }
            if(m >= n)
            {
                printf("0.00 ");
                continue;
            }
            sort(edge + 1 ,edge + nowid + 1 ,camp);
            printf("%.2lf " ,Search2(nowid));
        }
        return 0;
    }






    贪心+并查集


    #include<math.h>
    #include<stdio.h>
    #include<algorithm>


    using namespace std;


    typedef struct
    {
        int a ,b;
        double c;
    }EDGE;


    typedef struct
    {
        int  x ,y;
    }NODE;


    NODE node[500+5];
    EDGE edge[500*500/2+10];
    int mer[500+5];


    bool camp(EDGE a ,EDGE b)
    {
        return a.c < b.c;
    }


    int finds(int x)
    {
        return x == mer[x] ? x : mer[x] = finds(mer[x]);
    }


    double GetDis(NODE a, NODE b)
    {
        double x = (a.x - b.x) * (a.x - b.x);
        double y = (a.y - b.y) * (a.y - b.y);
        return sqrt(x + y);
    }




    int main ()
    {
        int t ,n ,m ,i ,j;
        scanf("%d" ,&t);
        while(t--)
        {
            scanf("%d %d" ,&m ,&n);
            int nowid = 0;
            for(i = 1 ;i <= n ;i ++)
            {
                mer[i] = i;
                scanf("%d %d" ,&node[i].x ,&node[i].y);
                for(j = 1 ;j < i ;j ++)
                {
                    ++nowid;
                    edge[nowid].c = GetDis(node[i] ,node[j]);
                    edge[nowid].a = i ,edge[nowid].b = j;
                }
            }
            if(m >= n)
            {
                printf("0 ");
                continue;
            }
            sort(edge + 1 ,edge + nowid + 1 ,camp);
            int edges = 0;
            for(i = 1 ;i <= nowid ;i ++)
            {
                int x = finds(edge[i].a);
                int y = finds(edge[i].b);
                if(x == y)continue;
                edges ++;
                mer[x] = y;
                if(edges + m >= n)
                {
                    printf("%.2lf " ,edge[i].c);
                    break;
                }
            }


        }
        return 0;
    }









  • 相关阅读:
    VSCODE记录
    关闭vscode的C/C++代码错误提示
    Windows下修改VSCode工作区存储目录workspaceStorage
    取消掉远程桌面mstsc顶部(侧面)连接栏
    记一次某网站生产环境CPU忽高忽低故障解决过程
    HTML实现发送接收串口和TCP数据
    flutter环境管理工具fvm的安装及简单使用
    启动CAD,不打开指定的CAD,向指定的CAD写入数据
    JVM虚拟机垃圾回收
    JVM调优命令
  • 原文地址:https://www.cnblogs.com/csnd/p/12062502.html
Copyright © 2011-2022 走看看