HDOJ 2585 maximum shortest distance(求最大团+二分)

maximum shortest distance

Time Limit: 2000/1000 MS(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1879    Accepted Submission(s): 643

Problem Description

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

 

 

Input

For each case, the first linecontains two integers n and k. The following n lines represent n points. Eachcontains 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 totwo decimal places.

 

 

Sample Input

3 2

0 0

10 0

0 20

 

 

Sample Output

22.36


开始套用之前总结的模板,怎么也过不了,一直TLE,后来发现自己的模板还有可以优化的地方,加一个语句后就过了

虽然花了很长时间debug,但优化了代码还是很值得的


#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
const int maxn = 55;
const int mod = 9973;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
#define ll long long
#define rush() int T;scanf("%d",&T);while(T--)
bool link[maxn][maxn]; //各点间的连接关系
int dp[maxn];         //记录以i出发构成的最大团顶点数量(从i到n-1的最大团)
int stk[maxn][maxn];  //第i层中与之相连的第j大的标号
int mx;               //最后的结果
double dis[maxn][maxn];
struct node
{
    int x,y;
} a[maxn];
double getdis(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//一共有n个点,dep表示当前的层数,ns代表与当前层相连并且比ns大的标号个数
int dfs(int n,int ns,int dep)
{
    if(ns==0)
    {
        if(dep>mx)
        {
            mx=dep;
            return 1;
        }
        return 0;
    }
    for(int i=0;i<ns;i++)
    {
        if(ns+dep-i<=mx)       //此次优化之处
            return 0;
        int k=stk[dep][i];     //与之相连的第i个点
        if(dep+n-k<=mx)        //若当前顶点数量加上还能够增加的最大数量仍小于当前最优解则退出;
            return 0;          //若当前顶点数量加上dp[k]仍小于当前最优解则退出;
        if(dep+dp[k]<=mx)
            return 0;
        int cnt=0;
        for(int j=i+1;j<ns;j++)
        {
            int p=stk[dep][j];   //i后边的某个点
            if(link[k][p])       //如果i和j相连
                stk[dep+1][cnt++]=p;
        }
        if(dfs(n,cnt,dep+1))
            return 1;
    }
    return 0;
}

int maxclique(int n)
{
    mx=0;
    for(int i=n-1; i>=0; i--)
    {
        int ns=0;
        for(int j=i+1; j<n; j++)
        {
            if(link[i][j])
                stk[1][ns++]=j;
        }
        dfs(n,ns,1);
        dp[i]=mx;
    }
    return mx;
}

int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        for(int i=0; i<n-1; i++)
            for(int j=i+1; j<n; j++)
            {
                dis[i][j]=dis[j][i]=getdis(a[i],a[j]);
            }
        double l=0,r=15000;
        while(r-l>eps)
        {
            double m=(l+r)/2;
            for(int i=0;i<n-1;i++)
                for(int j=i+1;j<n;j++)
                {
                    link[i][j]=link[j][i]=(dis[i][j]>=m);
                }

            int ans=maxclique(n);
            if(ans>=k)
                l=m;
            else
                r=m;
        }
        printf("%.2lf\n",l);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值