zoukankan      html  css  js  c++  java
  • UVA 10245 The Closest Pair Problem

    UVA_10245

    这个题目又是对我传统思维的一个撞击,一开始是怎么也想象不到会存在N^2的复杂度还小的算法,后来看了别人的博客之后才发现原来这个题目要用分治的思想。

    首先我们把坐标按x升序进行排列,然后定义LR分别为区间的左右端点(LR均代表点的标号),mid为区间中点,我们可以先分别暴力求出在[L,mid][mid,R]中最短的线段,不妨设其为min,当然最短线段还可能是两个点分别在两个区间之中,但如果存在这样的最短线段,那么线段的两个端点一定会在区间[a,b]中,并且x[mid]-x[a]>=minx[b]-x[mid]>=min,因为两点之间的距离大于等于两点横坐标差的绝对值。

    这样我们便可以写一个迭代函数来实现这一过程。迭代函数中首先要不断二分区间,然后分别去求区间内的最短线段的值并合并,最后以mid为中心,分别向左向右依次扫描可能是最短的跨区间的线段即可,如果长度确实比min小,更新min即可。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<math.h>
    double x[10010],y[10010];
    int r[10010];
    int cmp(const void *_p,const void *_q)
    {
    int *p=(int *)_p;
    int *q=(int *)_q;
    return x[*p]>x[*q]?1:-1;
    }
    double dis(int i,int j)
    {
    return sqrt((x[j]-x[i])*(x[j]-x[i])+(y[j]-y[i])*(y[j]-y[i]));
    }
    double min(double p,double q)
    {
    return p<q?p:q;
    }
    double f(int L,int R)
    {
    int i,j,k,mid;
    double ans,temp;
    if(L==R)
    return 1000000000.0;
    if(L==R-1)
    return dis(r[L],r[R]);
    mid=(L+R)/2;
    ans=min(f(L,mid),f(mid,R));
    for(i=mid-1;i>=L&&x[r[mid]]-x[r[i]]<ans;i--)
    for(j=mid+1;j<=R&&x[r[j]]-x[r[mid]]<ans;j++)
    {
    temp=dis(r[i],r[j]);
    if(temp<ans)
    ans=temp;
    }
    return ans;
    }
    int main()
    {
    int i,j,k,N;
    double ans;
    while(1)
    {
    scanf("%d",&N);
    if(N==0)
    break;
    for(i=0;i<N;i++)
    {
    scanf("%lf%lf",&x[i],&y[i]);
    r[i]=i;
    }
    qsort(r,N,sizeof(r[0]),cmp);
    ans=f(0,N-1);
    if(ans<10000.0)
    printf("%.4f\n",ans);
    else
    printf("INFINITY\n");
    }
    return 0;
    }



  • 相关阅读:
    有7g和2g的砝码各一个,怎样称可以3次把140g东西分为50g和90g???????
    中缀到后缀(一个例子)
    动态代理模式的使用
    代理模式用来初始化的延迟下载
    ReentrantLock Condition 实现消费者生产者问题
    Two Sum
    [leetcode]重建二叉树(先序和终须) 中序遍和后续
    (转载)旋转数组查找 最简洁方法 总结
    [不明觉厉] 下一个排列
    codeforces -- 283A
  • 原文地址:https://www.cnblogs.com/staginner/p/2185689.html
Copyright © 2011-2022 走看看