LAN 질문입니다.

  • freestar
    freestar

    LAN 문제를 푸는 중입니다.
    테스트 케이스 다 맞고, 제가 추가로 만든 예제에서도 결과가 잘 나오는데
    제출하니 오답이라고 뜨네요.

    조언 부탁드립니다.

    방법은
    모든 node 사이 edge들의 weight를 구한뒤
    이미 있는 edge의 weight를 0으로 만들고
    최소 스패닝 트리 알고리즘을 썼습니다.

    #include <stdio.h>
    #include <math.h>
    
    typedef struct Edge{
    
        int n1;
        int n2;
        double dist;
    
    } EDGE;
    
    
    EDGE edge[124750];
    
    int X[500], Y[500];
    int C, N, M;
    
    EDGE tmp[124750];
    int c = 0;
    int cycle[500] = { 0, };
    
    double sum = 0.0;
    int num_edges = 0;
    
    void merge(int left, int mid, int right)
    {
    
        int l = left;
        int r = mid+1;
        int idx=0;
    
        while (l<=mid && r <=right)
        {
            if (edge[l].dist < edge[r].dist) tmp[idx++] = edge[l++];
            else tmp[idx++] = edge[r++];
        }
    
        while (l <= mid) tmp[idx++] = edge[l++];
        while (r <= right) tmp[idx++] = edge[r++];
    
        for (int i = left; i <= right; i++)
            edge[i] = tmp[i-left];
    
    }
    
    void merge_sort(int left, int right)
    {
        if (left < right)
        {
            int mid = (left + right) / 2;
            merge_sort(left, mid);
            merge_sort(mid + 1, right);
            merge(left, mid, right);
        }
    }
    
    void connect(int n1, int n2, double dist)
    {
        //NO Cycle
        if (cycle[n1] == 0 && cycle[n2] == 0)
        {
            c++;
            cycle[n1] = c;
            cycle[n2] = c;
            sum += dist;
            num_edges++;
        }
        else if (cycle[n1] != 0 && cycle[n2] == 0)
        {
            cycle[n2] = cycle[n1];
            sum += dist;
            num_edges++;
        }
        else if (cycle[n1] == 0 && cycle[n2] != 0)
        {
            cycle[n1] = cycle[n2];
            sum += dist;
            num_edges++;
        }
        else if (cycle[n1] != 0 && cycle[n2] != 0 && cycle[n1] != cycle[n2])
        {
            for (int j = 0; j < N; j++)
            {
                if (cycle[j] == cycle[n2])
                    cycle[j] = cycle[n1];
            }
            sum += dist;
            num_edges++;
        }
        //else -> Cycle!
    }
    
    int main()
    {
        int i;
        int a, b;
        int total_edges;
    
        scanf("%d", &C);
        while (C--)
        {
            scanf("%d %d", &N, &M);
            for ( i = 0; i < N; i++)
                scanf("%d", &X[i]);
    
            for ( i = 0; i < N; i++)
                scanf("%d", &Y[i]);
    
    
            // 모든 node 간의 edge dist 구하기
            total_edges = 0;
            for (i = 0; i < N; i++)
            {
                for (int j = i + 1; j < N; j++)
                {
                    edge[total_edges].n1 = i;
                    edge[total_edges].n2 = j;
                    edge[total_edges].dist = sqrt(pow((double)(X[i] - X[j]), 2) + pow((double)(Y[i] - Y[j]), 2));
                    total_edges++;
                }
            }
    
            //이미 edge가 존재하면, 그 edge는 dist를 0으로 -> MST 만들때 가장 처음에 추가하기 위해
            for ( i = 0; i < M; i++)
            {
                scanf("%d %d", &a, &b);
                for (int j = 0; j < total_edges; j++)
                {
                    if ((edge[j].n1 == a && edge[j].n2 == b) || (edge[j].n1 ==b && edge[j].n2 == a))
                    {
                        edge[j].dist = 0;
                        //연결
                        connect(edge[j].n1, edge[j].n2, edge[j].dist);
                        break;
                    }
                }
            }
    
            merge_sort(0, total_edges - 1);
    
            for (i = 0; i < total_edges; i++)
            {
                //연결
                connect(edge[i].n1, edge[i].n2,edge[i].dist);           
                if (num_edges == N - 1) break;
            }
            printf("%.10lf\n", sum);
    
            c = 0;
            for (i = 0; i < N; i++)
                cycle[i] = 0;
    
            sum = 0.0;
            num_edges = 0;
        }
        return 0;
    }
    

    8년 전
3개의 댓글이 있습니다.
  • freestar
    freestar

    오류를 발견하고 수정 뒤 제출했습니다만, 여전히 오답 중인 상태입니다. 소스코드는 6/19일 오전 11시 20분쯤 업데이트 했습니다.


    8년 전 link
  • restart
    restart
    for (int j = 0; j < N; j++)
    {
        if (cycle[j] == cycle[n2])
            cycle[j] = cycle[n1];
    }
    

    이부분에서 cycle[n2]가 먼저 업데이트 될 경우 문제가 발생합니다ㅠㅠ cycle[n2]를 임시변수에 저장해두고 업데이트하니 정답이 뜨는군요. 이런 data structure를 union find 혹은 disjoint-set이라고 하고, 여기에 잘 짜여진 알고리즘이 있습니다.


    8년 전 link
  • freestar
    freestar

    와 정말 감사합니다. ㅠㅠ 긴 소스코드를 이렇게 봐주시고 답변 해주시다니.. 감사합니다.


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