hdoj 3585 maximum shortest distance(二分+最大团)

maximum shortest distance



Problem Description
There are n points in the plane. Your task is to pick k points (k>=2), and make the closest points in these k points as far as possible.
 

Input
For each case, the first line contains two integers n and k. The following n lines represent n points. Each contains two integers x and y. 2<=n<=50, 2<=k<=n, 0<=x,y<10000.
 

Output
For each case, output a line contains a real number with precision up to two decimal places.

 

Sample Input
  
  
3 2 0 0 10 0 0 20
 

Sample Output
  
  
22.36
 

Author
alpc50
 

Source

2分枚举可能的值m,本来是一个无向完全图,现在使图中只存在边长大于等于m的边
然后进行寻找最大团看是不是大于k
#include<cstdio>
using namespace std;
const int N=65;
int ans,f[N],set[N][N],a[N][N];//f[i]记录i-N中点构成的最大团的点的数量 记录的目的是为了剪枝
double b[N][N];
struct node
{
    double x,y;
}p[N];
double getdist(node a,node b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool dfs(int num,int dep)
{
    int i,j;
    if(!num)
    {
        if(dep>ans)
        {
            ans=dep;
            return 1;
        }//剪枝1 如果新加入的点与之前的最大团相连 因为不可能得到更大的dep了 所以return1
        return 0;
    }
    for(i=1;i<=num;i++)
    {
        if(dep+num-i+1<=ans)
            return 0;//剪枝2 如果当前已构成的团中点的数量加上剩余所有点的数量也没有超过ans 计算就没有意义了
        int u=set[dep][i];
        if(dep+f[u]<=ans)
            return 0;//剪枝3 如果当前的深度加上当前i点到最后一个点的最大团中点的数量还是也没有超过ans 计算就没有意义了
        int cnt=0;
        for(j=i+1;j<=num;j++)
            if(a[u][set[dep][j]])
                set[dep+1][++cnt]=set[dep][j];
        if(dfs(cnt,dep+1))
            return 1;//剪枝1
    }
    return 0;
}
int main()
{
    int n,i,j,num,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        double l=0,r=20000;
        for(i=1;i<n;i++)
            for(j=i+1;j<=n;j++)
            {
                b[i][j]=b[j][i]=getdist(p[i],p[j]);

            }
        while(r-l>1e-4)
        {
            double m=(r+l)/2;
            ans=0;
            for(i=1;i<n;i++)
                for(j=i+1;j<=n;j++)
                    a[i][j]=a[j][i]=(b[i][j]>=m*m);
            for(i=n;i>=1;i--)
            {
                num=0;
                for(j=i+1;j<=n;j++)
                    if(a[i][j])
                        set[1][++num]=j;
                dfs(num,1);
                f[i]=ans;
            }
            if(ans>=k)
                l=m;
            else
                r=m;
        }
        printf("%.2lf\n",l);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值