#include #include #define EPS 0.00001 /* our floating-point operations precision */ /* returns square of distance between [x1, y1] and [x2, y2] */ double dst(double x1, double y1, double x2, double y2) { return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); } /* returns 1, if infinite line AB intersects with line segment CD, otherwise returns 0. The intersection point is returned as [ix,iy] */ int intersects(double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy, double *ix, double *iy) { double u, v, s, t; /* CD: y = ux + v AB: y = sx + t */ double x, y, d; if (!ix) ix = &x; /* if ix, iy are 0, intersection point is not returned */ if (!iy) iy = &y; if (fabs(cx - dx) >= EPS) /* CD is not vertical */ { u = (dy - cy) / (dx - cx); v = cy - u * cx; } if (fabs(ax - bx) >= EPS) /* AB is not vertical */ { s = (by - ay) / (bx - ax); t = ay - s * ax; } if (fabs(cx - dx) < EPS) /* CD is vertical */ { if (fabs(ax - bx) < EPS) /* and also AB is vertical */ return 0; else /* only CD is vertical */ { *ix = cx; *iy = s * *ix + t; } } else /* CD is not vertical */ { if (fabs(ax - bx) < EPS) /* only AB is vertical */ { *ix = ax; *iy = u * *ix + v; } else /* neither AB, nor CD are vertical */ { if (fabs(u - s) < EPS) /* but they are parallel */ return 0; else /* a regular case */ { *ix = (t - v) / (u - s); *iy = u * *ix + v; } } } d = dst(cx, cy, dx, dy); if ((dst(*ix, *iy, cx, cy) - EPS < d) && (dst(*ix, *iy, dx, dy) - EPS < d)) return 1; /* inters. between C, D */ else return 0; /* ouside CD segment */ } /* returns the line from where distance to A and B is the same */ void make_symmetry_line(int ax, int ay, int bx, int by, double *x1, double *y1, double *x2, double *y2) { *x1 = (ax + bx) / 2; *y1 = (ay + by) / 2; /* first point is in the center of AB */ *x2 = *x1 + (by - ay); *y2 = *y1 - (bx - ax); /* second is obtained using the normal vector */ } int main() { int n, m, *xb, *yb, *xc, *yc; double x1, y1, x2, y2; int i, j, k, l, q, previous, count, closest; int *segments = 0; double *intx = 0, *inty = 0; double x, y, x0, y0, ox, oy, px, py, d, d2; int inters_borders; FILE *f; /* read input */ f = fopen("voronoi.in", "r"); fscanf(f, "%d", &n); xb = (int *) malloc((n + 1) * sizeof(int)); yb = (int *) malloc((n + 1) * sizeof(int)); for (i = 0; i < n; i++) fscanf(f, "%d%d", xb + i, yb + i); xb[i] = xb[0]; /* wrap around */ yb[i] = yb[0]; fscanf(f, "%d", &m); xc = (int *) malloc(m * sizeof(int)); yc = (int *) malloc(m * sizeof(int)); for (i = 0; i < m; i++) fscanf(f, "%d%d", xc + i, yc + i); fscanf(f, "%d%d%d%d", &i, &j, &k, &l); x1 = i; y1 = j; x2 = k; y2 = l; fclose(f); f = fopen("voronoi.out", "w+"); /* determine if the line intersects with the borders and move the x1, y1, x2, y2 to be on the border */ inters_borders = 0; for (i = 0; i < n; i++) if (intersects(x1, y1, x2, y2, xb[i], yb[i], xb[i + 1], yb[i + 1], &x, &y)) { if ((inters_borders++) && ((fabs(x - x0) > EPS) || (fabs(y - y0) > EPS))) break; x0 = x; y0 = y; } /* no intersection? */ if (!inters_borders) count = 0; else { if (inters_borders == 1) /* only touches the polygon */ { q = 2; intx = (double *) malloc(3 * sizeof(double)); inty = (double *) malloc(3 * sizeof(double)); intx[0] = intx[1] = x1 = x2 = x0; inty[0] = inty[1] = y1 = y2 = y0; } else { /* move [x1,y1], [x2,y2] to be on the border */ if (dst(x1, y1, x, y) < dst(x1, y1, x0, y0)) { x1 = x; y1 = y; x2 = x0; y2 = y0; } else { x1 = x0; y1 = y0; x2 = x; y2 = y; } /* make a list of intersections of a flight line with borders of voronoi diagram segments, and sort it with respect to x and y coordinate */ /* initialize the list */ intx = (double *) malloc((m * (m - 1) / 2 + 2) * sizeof(double)); inty = (double *) malloc((m * (m - 1) / 2 + 2) * sizeof(double)); q = 1; /* find the intersection point for each pair of voronoi sites */ for (i = 0; i < m; i++) for (j = i + 1; j < m; j++) { make_symmetry_line(xc[i], yc[i], xc[j], yc[j], &ox, &oy, &px, &py); if (intersects(ox, oy, px, py, x1, y1, x2, y2, &x, &y)) { /* find place to insert */ for (k = 1; (k < q) && ((x > intx[k]) || ((x == intx[k]) && (y > inty[k]))); k++); /* make space */ for (l = q; l > k; l--) { intx[l] = intx[l - 1]; inty[l] = inty[l - 1]; } /* store */ intx[k] = x; inty[k] = y; q++; } } /* adjust the order to reflect the distance from [x1,y1] */ if ((x1 > x2) || ((fabs(x1 - x2) < EPS) && (y1 > y2))) for (k = 1; k <= (q >> 1); k++) { x = intx[k]; intx[k] = intx[q - k]; intx[q - k] = x; y = inty[k]; inty[k] = inty[q - k]; inty[q - k] = y; } intx[0] = x1; inty[0] = y1; intx[q] = x2; inty[q] = y2; q++; } intx[q] = x2 + 1; /* to avoid skip at the end */ /* test all centers of all segments */ previous = -1; count = 0; segments = (int *) malloc(m * sizeof(int)); for (i = 0; i < q - 1; i++) { /* if more than 2 lines met in the same point, skip */ if ((fabs(intx[i + 2] - intx[i]) < EPS) && (fabs(inty[i + 2] - inty[i]) < EPS)) continue; x = (intx[i] + intx[i + 1]) / 2; y = (inty[i] + inty[i + 1]) / 2; /* find the closest voronoi site */ closest = 0; d = 200.0; for (j = 0; j < m; j++) if ((d2 = dst(x, y, xc[j], yc[j])) < d) { d = d2; closest = j; } if (closest != previous) segments[count++] = closest; previous = closest; } } /* write output */ fprintf(f, "%d\n", count); for (i = 0; i < count; i++) fprintf(f, "%d ", segments[i] + 1); if (count) fprintf(f, "\n"); fclose(f); if (segments) free(segments); if (intx) free(intx); if (inty) free(inty); free(xc); free(yc); free(xb); free(yb); return 0; }