分治法—hdu1007

 分治法吧,我也是第一次做题。就以我的理解对hdu1007来讲一下到目前为止我对分治法的理解吧。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1007

题意:题意很清楚,就是求一个平面内的最近点对,然后输出最近点对距离的一半。

思路:首先能想到的肯定是直接暴力。但是我们看这个数据10e5,直接暴力的话铁定超时,所以就不得不用分治了。。

所谓分治就是先把对应点的x坐标排序,然后再分别求出两部分的最小的距离d1和d2,d=min(d1,d2),当然,当我们把x分为两部分时,然后再递归二分吧,每次到还剩两个数据时直接求出他们的距离。每次返回都和d取最小值。当然这样我们还没有计算不同区间的距离,这个比较重要,我们每次都把各个数据的x和d比较,>的话就肯定不行的了,然后记录<=的数据,另设数组保存。再判断y与d的关系,>的话,肯定也是不行的了。其实我的理解分治就是优化时间复杂度的吧,要是能暴力该有多好。

ac代码:

#include<iostream>
#include<algorithm>
#include<math.h>
#define INF 0x3f3f3f3f
#define maxn 100010
using namespace std;
struct note
{
    double x,y;
};
note p[maxn],t[maxn];
int cmpxy(note a,note b)
{
    if(a.x==b.x)
    return a.y<b.y;
    return a.x<b.x;
}
int cmpy(note a,note b)
{
    return a.y<b.y;
}
double dis(note a,note b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));//计算两点间的距离 
}

double closet(int left,int right)
{
    double d=INF;//赋初值为极大 
    if(left==right)
    return d;//一个点时,直接返回极大 
    if(left+1==right)//当分到只剩两个点时直接算出他们的距离 
    {
        return dis(p[left],p[right]);
    }
    int mid=(left+right)/2;//算中间值 
    double d1=closet(left,mid);
    double d2=closet(mid+1,right);//递归 
    d=min(d1,d2);//更新小值 
    int k=0;
    for(int i=left;i<=right;i++)
    {
        if(fabs(p[i].x-p[mid].x)<=d)//大于d的就不要了 
        t[k++]=p[i];
    }
    sort(t,t+k,cmpy);//以y的值由小到大排序 
    for(int i=0;i<k;i++)
    {
        for(int j=i+1;j<k&&t[j].y-t[i].y<d;j++)//大于d就不要了 
        {
            
            d=min(d,dis(t[i],t[j]));//更新d的值,直到找到最小 
        }
    }
    return d;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF&&n)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        sort(p,p+n,cmpxy);//排序,以x的坐标由小到大排序 
        printf("%.2lf\n",closet(0,n-1)/2);//输出最小的值的一半 
        
    }
    return 0;
 } 

你窥探过我最不安的手,在青春最寒冷的时候。

猜你喜欢

转载自www.cnblogs.com/2000liuwei/p/10638587.html