closest pair 알고리즘 문제 관련 질문입니다.

  • canuyes
    canuyes

    글을 오리고보니 소스가 가독성이 없네요 ㅠㅠ
    제 소스는 http://kldp.org/node/138205 에가시면 보기 좋게 나와있습니다ㅠㅠ

    안녕하세요.
    현재 closest pair을 공부중인 학생입니다.
    closest pair 문제는 아래와 같습니다.

    평면에 n개의 점이 주어졌을때, n개의 점들중 최소 거리에 있는 점들의 거리의 제곱을 출력하라.
    제한조건은 100000에 실행시간 1초, 용량 128mb이내 입니다.

    저는 divide & conquer를 이용하여 문제를 풀기 원합니다.
    따라서 여러가비 방법으로 시도를 해보았지만, 자꾸 메모리 초과에 부딫힙니다....

    아래는 제가 짠 코드이고, 그 아래에 있는 코드는 구글링을 통해 얻은 정답 코드입니다. 크게 다른 점은 없어보이는데, 제 코드는 자꾸 메모리 초과가 뜨네요....

    제 코드와의 다른 점을 알려주시면 감사하겟습니다.
    여기에서 본 문제는 아니지만 활성화된 알고리즘 커뮤니티가 여기뿐
    이네요...ㅠㅠ

    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #define MAX_DIST 1000000000
    using namespace std;
    struct DOT{int x;int y;};
    DOT xet[100000];
    DOT yet[100000];
    //정렬시에 사용될 함수입니다.
    inline int comp_x(const void* A,const void* B){return ((DOT*)A)->x-((DOT*)B)->x;}
    inline int comp_y(const void* A,const void* B){return ((DOT*)A)->y-((DOT*)B)->y;}
    //두 값중 작은 값을 리턴하는 함수입니다.
    inline int smaller(const int A,const int B){if(A<B){return A;}return B;}
    //두점 사이의 거리를 계산하는 함수입니다.
    inline int DIST(const DOT A,const DOT B){return ((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
    //점의 갯수가 8개 이하일때, 단순하게 O(n^2)으로 답을 구합니다.
    inline int brute_force(DOT* arr,int size){
        int i,j,ret=MAX_DIST;
        for(i=0;i<size-1;i++){for(j=i+1;j<size;j++){ret=smaller(ret,DIST(arr[i],arr[j]));}}
        return ret;
    }
    //답을 만들어내는 함수입니다.
    inline int mkANS(DOT* xet,DOT* yet,int size){
        int ret=MAX_DIST;
        //점의 갯수가 8개 이하일 경우 brute_force를 호출합니다.
        if(size<9){ret=brute_force(xet,size);}
        else{
            //pivot에 x축 기준으로 가운댓 점의 x좌표를 대입합니다.
            int i,dist,L=-1,R=size,pivot=xet[size/2].x;
            //yyet를 생성하여 pivot보다 x좌표가 작은 점은 yyet의 왼쪽에,
            //pivot보다 x좌표가 큰점은 오른 쪽에 저장합니다.
            //이때, y축 기준으로 정렬된 yet 순차적으로 저장하므로
            //yyet의 왼,오른 쪽은 자동으로 y축 오름 차순으로 정렬됩니다.
            DOT* yyet=new DOT[size];
            for(i=0;i<size;i++){
                if(yet[i].x-pivot<=0){yyet[++L]=yet[i];}
                else{yyet[--R]=yet[i];}
            }
            //왼쪽 점의 갯수,오른쪽 점의 갯수를 알아 내었으므로 왼쪽 오른 쪽에 대해 다시 재귀 호출합니다.
            ret=smaller(mkANS(xet,yet,L+1),mkANS(xet+L+1,yet+L+1,size-L-1));
            //위에서 구해진 왼쪽 점끼리로만 만들어진 최소거리와 오른 쪽점들로만 만들어진 최소거리중 더 작은 값으로 부터
            //pivot에서 위의 값이내에 들어오는 점들을 yyet에 왼쪽부터 차례로 대입합니다.
            //이때 역시 yet를 순차적으로 탐색하므로 yyet에는 자동적으로 y축에 대해 정렬된 값들이 저장됩니다.
            L=-1;
            for(i=0;i<size;i++){
                dist=(yet[i].x-pivot)*(yet[i].x-pivot);
                if(dist>=ret){continue;}
                else{yyet[++L]=yet[i];}
            }
            //왼쪽, 오른쪽을 가로 지르는 경우, y축 오름차순으로 이웃하는 점끼리만 고려해주면 되므로
            //아래의 비교를 수행합니다.
            for(i=0;i<=L-1;i++){ret=smaller(ret,DIST(yyet[i],yyet[i+1]));}
            delete []yyet;
        }
        return ret;
    }
    int main(void){
        int i,N;cin>>N;
        for(i=0;i<N;i++){cin>>xet[i].x>>xet[i].y;}
        memcpy(yet,xet,sizeof(DOT)*N);
        //xet에 x축 기준으로 정렬하여 저장합니다.
        qsort(xet,N,sizeof(DOT),comp_x);
        //yet에 y축 기준으로 정렬하여 저장합니다.
        qsort(xet,N,sizeof(DOT),comp_y);
        cout<<mkANS(xet,yet,N)<<endl;
        return 0;
    }
    

    정답인 코드는 제것이 아니기 때문에 링크로 대신합니다..
    http://rosettacode.org/wiki/Closest-pair_problem/C


    10년 전
2개의 댓글이 있습니다.
  • JongMan
    JongMan

    글쓸때 밑에 도움말 보시면 소스코드를 어떻게 하이라이트하는지 나와있습니다. 우선 제가 변경해 두었습니다. 채점은 어디에서 받을 수 있나요?


    10년 전 link
  • canuyes
    canuyes

    답변 감사합니다^^
    사이트 이용이 익숙지 않아 간단한 도움말 마저 확인하지 못한점 죄송합니다.

    일단 문제는 2일을 더 밤새며 고민한 끝에 풀어냈습니다.
    코드의 몇몇 부분에 오류가 있었던 것 같습니다.
    문제는 풀어냈지만 그래도 답변은 남기는 것이 예의 일것 같아 답글 남겨놓습니다.

    참고로 이 문제의 출처는 www.acmicpc.net 2261번 문제입니다.


    10년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.