[JSOI 2010] 部落划分
题目描述
原题戳我
对于任意一种部落划分的方法,都能够求出两个部落之间的距离,求出一种部落划分的方法,使靠得最近的两个部落尽可能远离(一共分成\(K\)个部落)。
例如,下面的左图表示了一个好的划分,而右图则不是。
题目解答
冷静分析
这题目太简单了
这题目一看就知道考并查集(其实是最小生成树变体),每次将距离最短的两个野村子部落融入到一个大部落中即可,然后剩\(K\)个集合时中断合并即可。
程序实现
在最小生成树的算法基础上加一个中断条件即可,至于距离,初始化稍微弄弄就行了,不过避开小数运算的好办法是保留平方,最后再开根即可。代码如下:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#define M 1000005
using namespace std;
int r = 0, x[1005], y[1005], n, k;
int ffind[1005];
struct E
{
int a, b, dist;
}e[M];
bool cmp(E a, E b)
{
return a.dist < b.dist;
}
int Dist(int i, int j)
{
int a = x[j] - x[i], b = y[j] - y[i];
return a * a + b * b;
}
int Find(int x)
{
if(x != ffind[x])
ffind[x] = Find(ffind[x]);
return ffind[x];
}
inline void Together(int a, int b)
{
ffind[Find(a)] = Find(b);
}
int main()
{
int i, j;
float ans;
scanf("%d %d", &n, &k);
for(i = 0; i < n; i++)
{
scanf("%d %d", &x[i], &y[i]);
ffind[i] = i;
}
for(i = 0; i < n; i++)
for(j = i + 1; j < n; j++)
{
e[r].a = i;
e[r].b = j;
e[r++].dist = Dist(i, j);
}
ans = n;
sort(e, e + r, cmp);
for(i = 0; i < r; i++)
if(Find(e[i].a) != Find(e[i].b))
{
Together(ffind[e[i].a], ffind[e[i].b]);
if(ans == k)
{
ans = sqrt(e[i].dist);
break;
}
else ans --;
}
printf("%.2f", ans);
return 0;
}
尾注
这可能是我写的很不认真的一个题解了
写在最后
感谢大家的关注和阅读。
本文章借鉴了少许思路,最后经过本人思考独立撰写此文章,如需转载,请注明出处。