题解 洛谷 P4047 【[JSOI2010]部落划分】

我觉得几乎就是一道最小生成树模板啊...

题解里许多大佬都说选第n-k+1条边,可我觉得要这么讲比较容易理解

(虚边为能选的边,实边为最小生成树)

令n=5,k=2,(1,3)<(1,2)<(3,4)<(4,5)(PS:(4,5)<(2,5),图画错了,见谅)

然后开始分部落(被同一个三角形套住的为一个部落的):

(1)

这样肯定不为最优部落划分,因为他们的距离为(1,3)

(2)

同理,这样也不行

(3)

这样当然是不行的

所以,我们得出了这样一个结论:

要尽量选大边

所以小边要尽量在一个部落里,即下图:

又因为有k个部落,所以可以消掉(n-1)-(k-1)条边,所以最小的为第n-k+1条边,所以就输出a[n-k+1]

代码如下:

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
    int r=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1,c=getchar();}
    while(c>='0'&&c<='9')r=(r<<1)+(r<<3)+c-'0',c=getchar();
    return r*f;
}
struct E{
    int u,v;
    double dis;//记得为double
}e[10000001];
int f[10001],s_e,n,m;
int find(int x){
    if(f[x]!=x)f[x]=find(f[x]);
    return f[x];
}
inline bool cmp(E a,E b){
    return a.dis<b.dis; 
}
double a[10001];//记得为double
int x[10001],y[10001];
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)f[i]=i,x[i]=read(),y[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++){
            s_e++;
            e[s_e].u=i;
            e[s_e].v=j;
            e[s_e].dis=(double)sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));//计算sqrt((x1-x2)^2+(y1-y2)^2),即距离
        }
    sort(e+1,e+1+s_e,cmp);//最小生成树
    int i=1;
    int j=0;
    while(j<n-1){
        int fu=find(e[i].u),fv=find(e[i].v);
        double dis=e[i].dis;//记得为double
        if(fu!=fv){
            f[fu]=fv;
            j++;
            a[j]=dis;//记得为double
        }
        i++;
    }
    printf("%.2lf",a[n-m+1]);//记得是小数点后两位两位
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wyzwyz/p/10859072.html
今日推荐