P4047 [JSOI2010]部落划分
算法
最小生成树
思路
我们把每个点看成一个部落,每次取最小距离的两个抱团,同时部落也减少了一个....然后减减减,直到部落数==目标数,此时下一个不同部落的距离就是最短的距离!
代码
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cmath> const int MA = 1e7; using namespace std; int o,n,k,num,flag; int fa[MA]; inline int read() { int x = 0; char c = getchar(); while (!isdigit(c))c = getchar(); while(c>='0'&&c<='9') { x = x*10+c-'0'; c = getchar(); } return x; } struct s { int x,y;double l; }ass[MA],e[MA];//结构体存点; double cmp(s x,s y) { return x.l < y.l;} //比较边长; // int find(int a) { if(fa[a]!=a) fa[a] = find(fa[a]); return fa[a]; } void unionn(int a,int b) { fa[find(b)] = find(a); } //并查集; void kruskal() { for(int i=1;i<=o;i++) { if(num==n-k) flag = 1; if(find(e[i].x)!=find(e[i].y)) { num++; unionn(e[i].x,e[i].y); if(flag){ printf("%.2lf",e[i].l); return ;//写在里面,因为要不同的部落距离; } } } } double measure(int a,int b)//求欧几里得距离 { return sqrt(pow((ass[a].x-ass[b].x),2)+pow((ass[a].y-ass[b].y),2)); } int main() { n = read(),k = read(); for(int i=1;i<=n;i++) ass[i].x = read(),ass[i].y = read(); o = 0;//边数; for(int i=1;i<=n;i++) for(int j=1;j<i;j++) { if(i!=j)e[++o].x=i,e[o].y=j,e[o].l=measure(i,j); //为所有的点建边; } for(int i=1;i<=n;i++) fa[i] = i; sort(e+1,e+1+o,cmp); kruskal(); return 0; }
细雨斜风作晓寒,
淡烟疏柳媚晴滩。
入淮清洛渐漫漫。
雪沫乳花浮午盏,
蓼茸蒿笋试春盘。
人间有味是清欢。