zoukankan      html  css  js  c++  java
  • ※P4047 [JSOI2010]部落划分

    一眼二分:
    二分出最近的两个部落之间的最大距离,判断当前mid距离下能否划分成k个连通块

    const int N=1010;
    PII a[N];
    int p[N];
    double dist[N][N];
    int n,k;
    
    double dis(PII a,PII b)
    {
        return sqrt((a.fi-b.fi)*(a.fi-b.fi)+(a.se-b.se)*(a.se-b.se));
    }
    
    int find(int x)
    {
        if(x != p[x]) p[x]=find(p[x]);
        return p[x];
    }
    
    bool check(double mid)
    {
        for(int i=0;i<n;i++) p[i]=i;
    
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
            {
                if(dist[i][j] > mid) continue;
                int pi=find(i),pj=find(j);
                p[pi]=pj;
            }
    
        int cnt=0;
        for(int i=0;i<n;i++)
            if(p[i] == i)
                cnt++;
        return cnt>=k;
    }
    
    int main()
    {
        cin>>n>>k;
    
        for(int i=0;i<n;i++) cin>>a[i].fi>>a[i].se;
    
        double l=INF,r=0;
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
            {
                dist[i][j]=dis(a[i],a[j]);
                l=min(l,dist[i][j]);
                r=max(r,dist[i][j]);
            }
    
        for(int i=0;i<100;i++)
        {
            double mid=(l+r)/2;
            if(check(mid)) l=mid;
            else r=mid;
        }
    
        printf("%.2f\n",l);
    
        //system("pause");
    }
    

    贪心解法:

    • 要使得两个连通块之间的最短距离尽量大,则将距离短的点集构成一块连通块
    • \(kruskal\)每加一条边连通块数减一,于是采用\(kruskal\)算法求得k个的连通块
    • 则这k个连通块之间的边权大于任一连通块内的边权
    • 答案为使得k个连通块减少为k-1个连通块的边的权值
    const int N=1010;
    struct Node
    {
        int a,b;
        double c;
        bool operator<(const Node &W) const
        {
            return c<W.c;
        }
    }e[N*N];
    PII a[N];
    int p[N];
    int n,m,k;
    
    double dis(PII a,PII b)
    {
        return sqrt((a.fi-b.fi)*(a.fi-b.fi)+(a.se-b.se)*(a.se-b.se));
    }
    
    int find(int x)
    {
        if(x != p[x]) p[x]=find(p[x]);
        return p[x];
    }
    
    double kruskal()
    {
        for(int i=0;i<n;i++) p[i]=i;
    
        int sum=n;
        for(int i=0;i<m;i++)
        {
            int a=e[i].a,b=e[i].b;
            double c=e[i].c;
            int pa=find(a),pb=find(b);
            if(pa != pb)
            {
                p[pa]=pb;
                sum--;
                if(sum == k-1) return c;
            }
        }
    }
    
    int main()
    {
        cin>>n>>k;
    
        for(int i=0;i<n;i++) cin>>a[i].fi>>a[i].se;
    
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
                e[m++]={i,j,dis(a[i],a[j])};
    
        sort(e,e+m);
    
        double t=kruskal();
        printf("%.2f\n",t);
    
        //system("pause");
    }
    
  • 相关阅读:
    STM32F103ZET6 PWM输出
    STM32F103ZET6串口通信
    STM32F103ZET6系统定时器SysTick
    STM32F103ZET6的基本定时器
    npm 安装vue cli脚手架报错 npm err code EEXIST 或者 npm err cb<> never called 解决方案
    Java调用第三方http接口的方式
    机器学习算法原理解析
    Spark MLlib 机器学习
    Spark SQL基本概念与基本用法
    HBase基本概念与基本使用
  • 原文地址:https://www.cnblogs.com/fxh0707/p/13631705.html
Copyright © 2011-2022 走看看