题意:

      给你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\n");

            continue;

        }

        sort(edge + 1 ,edge + nowid + 1 ,camp);

        printf("%.2lf\n" ,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\n");

            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\n" ,edge[i].c);

                break;

            }

        }

    }

    return 0;

}

POJ2349二分+并查集,类似最小树的贪心的更多相关文章

  1. HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

  2. 洛谷P2498 [SDOI2012]拯救小云公主 【二分 + 并查集】

    题目 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1 ...

  3. 洛谷:P1783 海滩防御(二分+并查集 最短路 最小生成树)

    题意: 给定长度为N的海滩,然后有M做防御塔,给出每座塔的位置Xi,到海岸的距离Yi. 求防御塔上最小观测半径Ri,使得海滩被封锁. 思路:要使左边界和右边界连通. 很nice,可以二分+并查集做. ...

  4. [AGC002D] Stamp Rally 整体二分+并查集

    Description 给你一个n个点m个条边构成的简单无向连通图,有Q组询问,每次询问从两个点x,y走出两条路径,使这两条路径覆盖z个点,求得一种方案使得路径上经过的变的最大编号最小. Input ...

  5. 【BZOJ 1594】 [Usaco2008 Jan]猜数游戏 (二分+并查集)

    1594: [Usaco2008 Jan]猜数游戏 Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在牛棚后面 ...

  6. bzoj 1196: [HNOI2006]公路修建问题 二分+并查集

    题目链接 1196: [HNOI2006]公路修建问题 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1576  Solved: 909[Submit ...

  7. hdu3081 Marriage Match II(二分+并查集+最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意: n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她 ...

  8. 2018.11.02 NOIP模拟 飞越行星带(最小生成树/二分+并查集)

    传送门 发现题目要求的就是从下到上的瓶颈路. 画个图出来发现跟去年noipnoipnoip提高组的奶酪差不多. 于是可以二分宽度+并查集检验,或者直接求瓶颈. 代码

  9. P1783 二分并查集写法

    并查集 + 二分 我是 并查集 + 二分 做的QVQ 思路:两两枚举点之间的距离,sort排序,使距离有序.二分答案,每次判断是否符合条件,然后缩小查询范围,直到满足题目要求(保留2位小数精度就为 0 ...

随机推荐

  1. 【pytest官方文档】解读fixtures - 7. Teardown处理,yield和addfinalizer

    当我们运行测试函数时,我们希望确保测试函数在运行结束后,可以自己清理掉对环境的影响. 这样的话,它们就不会干扰任何其他的测试函数,更不会日积月累的留下越来越多的测试数据. 用过unittest的朋友相 ...

  2. 利用xslt与xml实现具体字段字母的大小写转换

    定义一个全局的变量 <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" ...

  3. 源码解析之 Mybatis 对 Integer 参数做了什么手脚?

    title: 源码解析之 Mybatis 对 Integer 参数做了什么手脚? date: 2021-03-11 updated: 2021-03-11 categories: Mybatis 源码 ...

  4. Python数据分析入门(一):搭建环境

    Python版本: 本课程用到的Python版本都是3.x.要有一定的Python基础,知道列表.字符串.函数等的用法. Anaconda: Anaconda(水蟒)是一个捆绑了Python.cond ...

  5. java例题_02 101~200以内的素数

    1 /*2 [程序 2 输出素数] 2 题目:判断 101-200 之间有多少个素数,并输出所有素数. 3 程序分析:判断素数的方法:用一个数分别去除 2 到 sqrt(这个数),如果能被整除,则表明 ...

  6. IOC容器模拟实现

    运用反射机制和自定义注解模拟实现IOC容器,使其具有自动加载.自动装配和根据全限定类名获取Bean的功能. 一. 实现原理 1-1 IOC容器的本质 IOC容器可理解为是一个map,其中的一个entr ...

  7. Async Cow Python 七牛异步SDK

    # Async Cow Python 七牛异步SDK > gitee链接 >github链接本SDK基于官方SDK改造而成,但又对其进行了进一步封装,简化了相关操作例如:- 1.不需要使用 ...

  8. jenkins构建go及java项目

    jenkins构建go及java项目 转载请注明出处https://www.cnblogs.com/funnyzpc/p/14554017.html 写在前面 jenkins作为java的好基友,经历 ...

  9. 无法打开“&#215;&#215;&#215;”,因为无法确认开发者的身份——解决办法

    当打开这些应用程序时,系统提示无法打开" XXX",因为它来自身份不明的开发者.我们可以按照下面的方法解决. 教程 1.打开应用程序,找到你要打开的软件.按住control键,点击 ...

  10. 有了CMDB,为什么还需要应用配置管理?

    有了CMDB,为什么还需要应用配置管理? 你不妨先停下来,思考一下这个问题. 我抛出的观点是: CMDB是面向资源的管理,应用配置是面向应用的管理. 请注意,这里是面向"资源",不 ...