• [JSOI2010]部落划分


    嘟嘟嘟

    一道不错的题,解法不少。

    最易于理解的是最小生成树的做法:

    首先每两个点之间都连一条长度为这两个点的距离的边,形成完全图。

    然后跑最小生成树,直到剩k个联通块,这时候合并成k - 1个联通块的边的长度就是答案(注意,是连接两个联通块的边,否则就不是部落间的距离了)。

    正确性很显然。因为这保证了部落内的距离尽量小,则部落外的距离尽量大,所以靠的最近的两个部落也就尽可能的远离。

    还有一种二分答案的方法:

    每一次把距离小于mid的点都划分成一个部落,最后看形成的部落总数和k的关系,如果小于k,向左二分;否则向右二分。

    时间复杂度都是O(ElogE),E为边数,等于n * (n - 1) / 2。(最小生成树算法排序时间O(ElogE),跑kruskal时时O(E)的)

    方法一的代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 1e3 + 5;
    21 const int maxe = 5e5 + 5;
    22 inline ll read()
    23 {
    24     ll ans = 0;
    25     char ch = getchar(), last = ' ';
    26     while(!isdigit(ch)) {last = ch; ch = getchar();}
    27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    28     if(last == '-') ans = -ans;
    29     return ans;
    30 }
    31 inline void write(ll x)
    32 {
    33     if(x < 0) x = -x, putchar('-');
    34     if(x >= 10) write(x / 10);
    35     putchar(x % 10 + '0');
    36 }
    37 
    38 int n, k;
    39 struct Node
    40 {
    41     int x, y;
    42 }a[maxn];
    43 struct Edge
    44 {
    45     int x, y; ll c;
    46     bool operator < (const Edge &oth)const
    47     {
    48         return c < oth.c;
    49     }
    50 }e[maxe];
    51 int ecnt = 0;
    52 
    53 ll calc(Node a, Node b)
    54 {
    55     return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
    56 }
    57 
    58 int p[maxn];
    59 void init()
    60 {
    61     for(int i = 1; i <= n; ++i) p[i] = i;
    62 }
    63 int Find(int x)
    64 {
    65     return x == p[x] ? x : p[x] = Find(p[x]);
    66 }
    67 
    68 int main()
    69 {
    70     n = read(); k = read(); 
    71     init();
    72     for(int i = 1; i <= n; ++i) a[i].x = read(), a[i].y = read();
    73     for(int i = 1; i < n; ++i)
    74         for(int j = i + 1; j <= n; ++j)
    75             e[++ecnt] = (Edge){i, j, calc(a[i], a[j])};
    76     sort(e + 1, e + ecnt + 1);
    77     int cnt = n;
    78     for(int i = 1; i <= ecnt; ++i)
    79     {
    80         int px = Find(e[i].x), py = Find(e[i].y);
    81         if(px != py)
    82         {
    83             if(cnt-- == k) {printf("%.2lf
    ", sqrt(e[i].c)); return 0;}
    84             p[px] = py;
    85         }
    86     }
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    php的函数
    php字符串
    PDA触屏的终极解决办法
    数字万用表 选购指南
    WindowsXp Sp2 英文版
    访问局域网某台电脑时提示:无法访问,你可能没有权限使用网络资源.的解决办法
    中华人民共和国国家标准职工工伤与职业病致残程度鉴定
    删除所有设备驱动的批处理
    如何制作Win XP操作系统映像文件
    使用批处理和devcon.exe来控制 Windows 的设备
  • 原文地址:https://www.cnblogs.com/mrclr/p/9839791.html
Copyright © 2020-2023  润新知