BOJ 28297 - 차량 모듈 제작

image.png

기하 문제이다.

모든 원 쌍을 $O(n^2)$에 검사하여 접하거나 $d < r_1+r_2$ 라면 DSU로 먼저 이어두자.

그렇지 않다면 두 원끼리 필요한 곡선의 길이를 그래프의 간선으로 두고 MST를 구성해줄 수 있다.

double PI = acos(-1);
double len(int x1, int y1, int r1, int x2, int y2, int r2) {
   if (r1 < r2) swap(x1, x2), swap(y1, y2), swap(r1, r2);
   double dx = abs(x1 - x2);
   double dy = abs(y1 - y2);
   double d = sqrt(dx * dx + dy * dy);

   double theta = acos((r1 - r2) / d);

   double ret = 0;

   double h = d * sin(theta);

   ret += h * 2;
   ret += 2 * PI * r2 * (theta / PI);
   ret += 2 * PI * r1 * ((2 * PI - 2 * theta) / (2 * PI));

   return ret;
}
struct DSU {
   vector<int> p;
   DSU(int n) : p(n, -1) {}
   int gp(int n) {
      if (p[n] < 0) return n;
      return p[n] = gp(p[n]);
   }
   void merge(int a, int b, int to_b = 0) {
      a = gp(a), b = gp(b);
      if (a == b) return;
      if (!to_b && size(a) > size(b)) swap(a, b);
      p[b] += p[a];
      p[a] = b;
   }
   bool is_merged(int a, int b) { return gp(a) == gp(b); }
   int size(int n) { return -p[gp(n)]; }
};
void solve() {
   int n;
   cin >> n;
   vector<array<int, 3>> a(n);
   vector<tuple<double, int, int>> edges;
   DSU dsu(n);
   for (auto &[x, y, r]: a) cin >> x >> y >> r;
   for (int i = 0; i < n; i++) {
      for (int j = i + 1; j < n; j++) {

         int dx = a[i][0] - a[j][0];
         int dy = a[i][1] - a[j][1];
         int rsum = a[i][2] + a[j][2];
         if (ll(dx) * dx + ll(dy) * dy <= ll(rsum) * rsum) {
            dsu.merge(i, j);
            debug(i, j);
            continue;
         }

         edges.pb({len(a[i][0], a[i][1], a[i][2], a[j][0], a[j][1], a[j][2]), i, j});
      }
   }
   sort(all(edges));
   double ans = 0;
   for (auto &[w, i, j]: edges) {
      if (!dsu.is_merged(i, j)) {
         debug(w, i, j);
         dsu.merge(i, j);
         ans += w;
      }
   }
   cout << setprecision(15) << fixed << ans;
}

Tags:

Categories:

Updated:

Comments