uva 10245 最近点对问题

分治法的典例

当练手了

神奇的是,使用inplace_merge按说应该是O(n)的算法,但是用sort nlogn的算法反而更快

先上快排版

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int SIZE = 10000+10;
const double INF = 100000;

struct Point
{
    double x,y;
}p[SIZE],q[SIZE];

int n;

inline double dis(const Point a, const Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool cmpx(const Point &a, const Point &b)
{
    return a.x<b.x;
}

bool cmpy(const Point &a, const Point &b)
{
    return a.y<b.y;
}

double MinDis(int l,int r)
{
    if(r-l<1)return INF;
    if(r-l==1)return dis(p[r],p[l]);

    int m=(l+r)/2;
    double d=min(MinDis(l,m),MinDis(m+1,r));
    int left=l,right=r+1;
    int i;
    for(i=m;i>=l;i--)
        if(p[i].x<p[m].x-d)
        {
            left=i+1;
            break;
        }
    for(i=m;i<=r;i++)
        if(p[i].x>p[m].x+d)
        {
            right=i;
            break;
        }
    for(int i=left;i<right;i++)q[i]=p[i];
    sort(q+left,q+right,cmpy);
    int j;
    double ret=d;
    for(int i=left;i<right;i++)
    {
        for(j=i+1;j<right && q[j].y-q[i].y<d;j++)
        {
            ret=min(ret,dis(q[i],q[j]));
        }
    }
    return ret;

}

int main()
{
    double ans;

    while(scanf("%d",&n)&&n)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        sort(p,p+n,cmpx);
        ans=MinDis(0,n-1);
        if(ans>10000)printf("INFINITY\n");
        else printf("%.4lf\n",ans);
    }

    return 0;
}

再上归并

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int SIZE = 10000+10;
const double INF = 100000;
#define dis(a,b) sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))
#define Fabs(x) x>0?x:-x
const double eps=1e-9;

struct Point
{
    double x,y;
}p[SIZE],q[SIZE];

int n;

/*inline double dis(const Point a, const Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}*/

bool cmpx(const Point &a, const Point &b)
{
    return a.x<b.x;
}

bool cmpy(const Point &a, const Point &b)
{
    return a.y<b.y;
}

double MinDis(int l,int r)
{
    if(r-l<1)return INF;
    //if(r-l==1)return dis(p[r],p[l]);

    int m=(l+r)/2;
    double d=min(MinDis(l,m),MinDis(m+1,r));
    inplace_merge(p+l,p+m+1,p+r+1,cmpy);
    int j,right=0;
    for(int i=l;i<=r;i++)//0 <n
        if(p[i].x >= p[m].x-d && p[i].x<=p[m].x+d)
            q[right++]=p[i];
    double ret=INF;
    for(int i=0;i<right;i++)
    {
        for(j=i+1;j<right && q[j].y-q[i].y<d;j++)
        {
            ret=min(ret,dis(q[i],q[j]));
        }
    }
    return min(d,ret);
}

int main()
{
    double ans;

    while(scanf("%d",&n)&&n)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        sort(p,p+n,cmpx);
        ans=MinDis(0,n-1);
        if(ans>=10000)printf("INFINITY\n");
        else printf("%.4lf\n",ans);
    }

    return 0;
}

uva 10245 最近点对问题,布布扣,bubuko.com

时间: 2024-10-13 23:29:08

uva 10245 最近点对问题的相关文章

uva 10245 The Closest Pair Problem (暴力+剪枝)

uva 10245 The Closest Pair Problem 题目大意:给出n个点,求出距离最近的两点间的距离.若点与点间的距离都大于10000,输出INFINITY 解题思路:这题的正统做法是分治,偷懒方法是暴力加剪枝.先按x坐标排序,然后fabs(p[i] - p[j]) > ans的点就可以直接跳过了. #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algori

UVA - 10245 The Closest Pair Problem

属于Divide-and-Conquer,算法课老师有讲到,就找个题目试试,思想就是不断的二分...考虑合并时的处理..不解释 //============================================================================ // Name : uva10245.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Uva10

uva 10245 近期点对问题

分治法的典例 当练手了 奇妙的是.使用inplace_merge按说应该是O(n)的算法.可是用sort nlogn的算法反而更快 先上快排版 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int SIZE = 10000+10; const doub

UVa 10245 The Closest Pair Problem (分治)

题意:给定 n 个点,求最近两个点的距离. 析:直接求肯定要超时的,利用分治法,先把点分成两大类,答案要么在左边,要么在右边,要么一个点在左边一个点在右边,然后在左边或右边的好求,那么对于一个在左边一个在右边的,我们可以先求全在左边或右边的最小值,假设是d,那么一个点在左边,一个点在右边,那么横坐标之差肯定小于d,才能替换d,同样的纵坐标也是,并且这样的点并不多,然后就可以先选出来,再枚举. 代码如下: #pragma comment(linker, "/STACK:1024000000,102

UVA 12325 Zombie&#39;sTreasureChest

看上去非常像背包的问题,但是体积太大了. 线性规划的知识,枚举附近点就行了,优先选性价比高的, 宝物有两种体积为S0,价值V0,体积S1,价值V1. 枚举分以下几种: 1:枚举拿宝物1的数量,然后尽量多拿宝物2:O(N/S0) 2:枚举拿宝物2的数量,同上:O(N/S1) 3.贪心,尽量选性价比高的 令gcd(S0,S1)= t,S1/t*S0 = S0/t*S1:体积相同的情况下尽量选价值高的,如果S1*V0>S0*V1大,那么枚举拿宝物2的数量,最多S0/t-1个否则一定可以换成S1/t个宝

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

UVA 10341 Solve It

Problem F Solve It Input: standard input Output: standard output Time Limit: 1 second Memory Limit: 32 MB Solve the equation: p*e-x + q*sin(x) + r*cos(x) + s*tan(x) + t*x2 + u = 0 where 0 <= x <= 1. Input Input consists of multiple test cases and te

UVA 11014 - Make a Crystal(容斥原理)

UVA 11014 - Make a Crystal 题目链接 题意:给定一个NxNxN的正方体,求出最多能选几个整数点.使得随意两点PQ不会使PQO共线. 思路:利用容斥原理,设f(k)为点(x, y, z)三点都为k的倍数的点的个数(要扣掉一个原点O).那么全部点就是f(1),之后要去除掉共线的,就是扣掉f(2), f(3), f(5)..f(n).n为素数.由于这些素数中包括了合数的情况,而且这些点必定与f(1)除去这些点以外的点共线,所以扣掉.可是扣掉后会扣掉一些反复的.比方f(6)在f

[UVa] Palindromes(401)

UVA - 401 Palindromes Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description A regular palindrome is a string of numbers or letters that is the same forward as backward. For example, the string "ABCDED