P4047 [JSOI2010]部落划分 (实数二分避免精度问题,最后开方)
想冲下100绿
这题说是MST,我看了之后直接想到了二分。
看了题解也不会MST
B U T BUT BUT 我好像知道有的时候我二分答案不会思考的问题了。
已经最近两个部落的距离是 mid ,判断能否满足 n 个点划分成 k 份?
首先:有两段性,可以二分答案。
我的想法是,有k份,每份都有啥呢?然后想到了并查集,有k个代表元素。从 n 个元素中选 k 个,然后再让其他点和这k个点比较,和哪个近就选哪个。
真是天才一般的想法 这复杂度没谁了。然后我就不会思考了。
看题解,人家都是这样思考的。从无到有 ,一开始啥都没有,如果两点距离小于mid就合并,最后看并查集代表元素和k的关系。
我思考的有问题的地方在于,我的判定没有直接用 mid!
然后我TM二分返回值也搞错了
当 cnt (并查集fa[i]==i) 的数量 小于 k 时,说明距离搞的太大了,否则说明距离太小了。
所以 : {cnt>=k, l = mid;} else r = mid;
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <sstream>
#define pb push_back
#define in insert
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+10,M=1e5+10;
int n,k;
int fa[N];
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
struct Node{
int l,r;
}node[1100];
double dist(Node x,Node y){
return (x.l-y.l)*(x.l-y.l)+(x.r-y.r)*(x.r-y.r);
}
bool ck(double mid){
fo(i,1,n)fa[i]=i;
int cnt = 0;
fo(i,1,n){
fo(j,i+1,n){
if(dist(node[i],node[j])<=mid)
fa[find(j)]=find(i);
}
}
fo(i,1,n)if(fa[i]==i)cnt++;
return cnt>=k;
}
void solve(){
cin>>n>>k;
fo(i,1,n){
cin>>node[i].l>>node[i].r;
}
double l = 0 , r = 1e9;
while(r-l>1e-4){
double mid = (l+r)/2;
// debug(mid);
if(ck(mid)){
l = mid;
}
else {
r = mid;
}
}
printf("%.2lf",sqrt(l));
}
int main()
{
solve();
return 0;
}