zoukankan      html  css  js  c++  java
  • JSOI2010 部落划分

    传送门

    这道题可以用二分答案做,但是我个人认为最小生成树做更为简洁。其实最小生成树并不准确,应该是最小生成森林。

    因为我们只要把所有部落连成k个块,然后让最近的块最远,所以我们肯定是连长度最小的边,那就是最小生成树咯。我们先建出一张完全图,之后跑一遍kruskal,每次如果属于不同集合的话把森林个数-1,直到满足要求。

    这题有一个坑,就是你在满足条件之后,再枚举的边可能是在集合之内,所以我们还得继续枚举一个集合之外的边,其边权就是答案。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 1000005;
    const int N = 1005;
    const int INF = 1000000009;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct edge
    {
        int next,to,from;
        double dis;
        bool operator < (const edge &g) const
        {
            return dis < g.dis;
        }
    }e[M<<1];
    
    struct node
    {
        double x,y;
    }a[1005];
    
    int n,k,fa[N],head[N],ecnt,cnt;
    
    double calc(int p,int q)
    {
        return sqrt((a[p].x - a[q].x) * (a[p].x - a[q].x) + (a[p].y - a[q].y) * (a[p].y - a[q].y));
    }
    
    void add(int x,int y,double z)
    {
        e[++ecnt].to = y;
        e[ecnt].from = x;
        e[ecnt].dis = z;
        e[ecnt].next = head[x];
        head[x] = ecnt;
    }
    
    int getfa(int x)
    {
        return (fa[x] == x) ? x : fa[x] = getfa(fa[x]);
    }
    
    int main()
    {
        n = read(),k = read();
        rep(i,1,n) fa[i] = i;
        rep(i,1,n) scanf("%lf%lf",&a[i].x,&a[i].y);
        rep(i,1,n)
           rep(j,i+1,n) add(i,j,calc(i,j));
        sort(e+1,e+1+ecnt);
        rep(i,1,ecnt)
        {
        int r1 = getfa(e[i].from),r2 = getfa(e[i].to);
        if(r1 != r2) fa[r2] = r1,cnt++;
        if(cnt == n - k) break;
        }
        cnt++;
        while(cnt <= ecnt)
        {
        int r1 = getfa(e[cnt].from),r2 = getfa(e[cnt].to);
        if(r1 != r2)
        {
            printf("%.2lf
    ",e[cnt].dis);
            break;
        }
        cnt++;
        }
        return 0;
    }
  • 相关阅读:
    PLC衔接新方式UcAsp.Opc
    dev barmanager 中的 add按钮出不来,无法创建菜单的问题解决
    一个或多个页边距被设置到也可打印的页面范围之外,处理方式
    bar设置全背景色
    PHP计算两个字符的相似程度similar_text
    PHP中双冒号::的用法
    百度站内搜索应该注意哪些方面?
    快给你的网站添加微信公众号吧!
    实例讲解网站前台界面开发流程
    百度富文本编辑器UEditor安装配置全过程
  • 原文地址:https://www.cnblogs.com/captain1/p/9853087.html
Copyright © 2011-2022 走看看