반응형

문제 출처 :


https://www.acmicpc.net/problem/9373



알고리즘 분석 :


문제 해결에 필요한 사항

1. 최소 스패닝 트리(MST) ::  http://www.crocus.co.kr/733


이 문제에 대한 접근은 다음과 같다.


우선 최소 스패닝 트리 개념으로 접근할 것이다.


1. 최소 스패닝 트리로 접근하기 위해 우선 센서와 복도를 생각해본다.


복도 좌, 우측 그리고 센서의 중심점을 각 정점으로 생각한다.


2. 이때 복도 좌측 x좌표는 0으로, 복도 우측 x좌표는 w로 생각하여 x좌표에 대해 정점들을 정렬한다.


이렇게 하는 이유는 최소 스패닝 트리에서 union을 쉽게 하기 위함이다.(큰 x좌표에서 작은 x좌표로 union한다는 개념으로)


3. 이때 인덱스 개념으로는 복도 좌측을 0번 인덱스, 복도 우측을 n + 1번 인덱스 그리고 센서를(센서의 반경을 하나의 부분 집합으로)

1~n번 인덱스로 생각한다.


4. 그렇게되면 n 범위가 최대 1000이기에 벽과 센서를 포함하여 모든 인덱스간의 간선을 구할 수 있다.


5. 그리고 그 간선들을 정렬하여 이제 최소 스패닝 트리 개념으로 접근한다.


6. 결국 크루스칼 알고리즘을 이용하여 해결하고, 두 벽이 연결되는 순간(find(0) == find(n+1)) 이 알고리즘은 종료된다.






소스 코드 : 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <memory.h>
#include <cmath>
 
using namespace std;
 
typedef long long ll;
 
typedef struct _INFO_
{
    int x;
    int y;
    int r;
    int idx;
}INFO;
 
// 크루스칼 알고리즘에 이용할 struct
typedef struct _KS_
{
    int from;
    int to;
    double val;
}KS;
 
INFO info[1002];
int parent[1002];
bool chk;
 
bool comp(const INFO &a, const INFO &b)
{
    return a.x < b.x;
}
bool compVC(const KS &a, const KS &b)
{
    return a.val < b.val;
}
 
double getLength(int x1, int x2, int y1, int y2)
{
    return sqrt((ll)(x1 - x2)*(x1 - x2) + (ll)(y1 - y2)*(y1 - y2));
}
 
int find(int u)
{
    if (u == parent[u])
        return u;
 
    return parent[u] = find(parent[u]);
}
 
void merge(int u, int v)
{
    chk = false;
    u = find(u);
    v = find(v);
 
    if (u == v)
        return;
 
    parent[u] = v;
    chk = true;
}
 
int main()
{
    int tCase;
    scanf("%d"&tCase);
 
    while(tCase--)
    {
        int w, n;
        scanf("%d %d"&w, &n);
        
        // 초기화
        memset(info, 0sizeof(info));
        vector<KS> vc;
        for (int i = 0; i <= n + 1; i++)
            parent[i] = i;
 
        info[0].x = 0;
        for (int i = 1; i <= n; i++)
            scanf("%d %d %d"&info[i].x, &info[i].y, &info[i].r);
        info[n + 1].x = w;
 
        // 왼쪽 벽, 오른쪽 벽을 제외하고 정렬
        sort(info + 1, info + n + 1, comp);
 
        // 왼쪽 벽의 idx = 0
        info[0].idx = 0;
 
        // 그 외의 정점들은 x를 오름차순 기준으로 idx 정렬
        for (int i = 1; i <= n; i++)
            info[i].idx = i;
 
        // 오른쪽 벽의 idx = n + 1
        info[n + 1].idx = n + 1;
 
        // 벽사이 거리를 먼저 push
        vc.push_back(KS{ info[n + 1].idx, info[0].idx, (double)w });
        
        for (int i = 1; i <= n; i++)
        {
            int x = info[i].x;
            int r = info[i].r;
 
            double len = max(0, x - r);
 
            vc.push_back(KS{ info[i].idx, info[0].idx, len });
 
            len = max(0, w - x - r);
            vc.push_back(KS{ info[n + 1].idx, info[i].idx, len });
        }
 
        // 정점 사이 길이들
        for(int j = 1; j < n; j ++)
            for (int k = j + 1; k <= n; k++)
            {
                int x1 = info[j].x;
                int y1 = info[j].y;
                int x2 = info[k].x;
                int y2 = info[k].y;
 
                double len = getLength(x1, x2, y1, y2);
 
                vc.push_back(KS{ info[k].idx, info[j].idx, max((double)0.0, len - (double)info[j].r - (double)info[k].r)});
            }
 
        sort(vc.begin(), vc.end(), compVC);
 
        for(int i = 0; i < vc.size(); i ++)
        {
            merge(vc[i].from, vc[i].to);
 
            if (chk == true)
            {
                if (find(0== find(n + 1))
                {
                    if (vc[i].val == 0)
                        printf("0\n");
                    else
                        printf("%.6lf\n", vc[i].val / 2);
                    break;
                }
            }
        }
 
    }
 
    return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus


반응형

'Applied > 알고리즘 문제풀이' 카테고리의 다른 글

[7616번] 교실로 가는 길  (0) 2017.04.09
[2316번] 도시 왕복하기  (4) 2017.04.08
[1793번] 타일링  (0) 2017.04.07
[4485번] 녹색 옷 입은 애가 젤다지?  (2) 2017.04.07
[2934번] LRH 식물  (0) 2017.04.07