zoukankan      html  css  js  c++  java
  • POJ 2693 Chocolate Chip Cookies 题解 (计算几何)

    题目Chocolate Chip Cookies (http://poj.org/problem?id=2693)

    Time Limit: 1000MS                         Memory Limit: 65536K

    Total Submissions: 1767                Accepted: 452

    Description

    Making chocolate chip cookies involves mixing flour, salt, oil, baking soda and chocolate chips to form dough which is rolled into a plane about 50 cm square. Circles are cut from the plane, placed on a cookie sheet, and baked in an oven for about twenty minutes. When the cookies are done, they are removed from the oven and allowed to cool before being eaten.

    We are concerned here with the process of cutting the first cookie after the dough has been rolled. Each chip is visible in the planar dough, so we need simply to place the cutter so as to maximize the number of chocolate chips contained in its perimeter.

    Input

    Standard input consists of a number of lines, each containing two floating point numbers indicating the (x,y) coordinates of a chip in the square surface of cookie dough. Each coordinate is between 0.0 and 50.0 (cm). Each chip may be considered a point (i.e. these are not President's Choice Cookies). Each chip is at a different position. There are at most 200 chocolate chips.

    Output

    Standard output consists of a single integer: the number of chocolate chips that can be contained in a single cookie whose diameter is 5 cm. The cookie need not be fully contained in the 50 cm square dough (i.e. it may have a flat side).

    Sample Input

    4.0 4.0

    4.0 5.0

    5.0 6.0

    1.0 20.0

    1.0 21.0

    1.0 22.0

    1.0 25.0

    1.0 26.0

    Sample Output

    4

    分析:

            该题目实际上是: 平面上有一组点(已知), 用一个半径为2.5(直径为5)的圆(盘)来覆盖这些点, 求所能覆盖的点的数目的最大值。其中包含点在圆周上的情形。

            解题思路: 对于每两个点, 可确定一个过这两个点的半径为2.5的圆, 求出在圆内和圆上的点的数目。最后,求最大值即可。

                           

            由两点A(x1, y1), B(x2, y2)和半经r求圆时,我们只需要求出圆心就可以唯一确定一个圆。

            其中线段AB的长度应不超过2r,否则所求的圆不存在。下面是求解的过程。

            1)  求出线段AB的垂直平分线  L: a*x + b*y + c = 0,其中a, b不全为0。

                 则L的一个方向向量为(b, -a), 将其单位化, 得到单位向量(ex, ey)。

                 其中 ex = b / sqrt(a*a + b*b),ey = -a / sqrt(a*a + b*b)。

                 注: sqrt(x)表示x的平方根。

            2)  设AB的中点为 C(x0, y0),所要求的圆心为 O(x, y)。

                 由勾股定理可得线段OC的长度 d = sqrt(r*r - AC*AC)

                 那么就可以求出O点的坐标了:

                       x = x0 + d * ex,y = y0 + d * ey

                 或   x = x0 -  d * ex, y = y0 - d * ey 

    源代码(C语言):

     1 #include <stdio.h>
     2 #include <math.h>
     3 
     4 #define eps 0.0000000001
     5 
     6 typedef struct s_point {
     7     double x, y;
     8 } Point;
     9 
    10 typedef struct s_line {    // line: a*x + b*y + c = 0
    11     double a, b, c;
    12 } Line;
    13 
    14 int equal(double x, double y) { 
    15     if (fabs(x - y) < eps) {
    16         return 1;
    17     }
    18     return 0;
    19 }
    20 
    21 // calculate the perpendicular bisector of line defined by p1 and p2
    22 Line bisector(Point p1, Point p2) {  
    23     Line line;
    24     if (equal(p1.x, p2.x)) {
    25         line.a = 0.0, line.b = 1.0, line.c = - (p1.y  + p2.y) / 2.0;
    26     } else if (equal(p1.y, p2.y)) {
    27         line.a = 1.0, line.b = 0.0, line.c = - (p1.x + p2.x) / 2.0;
    28     } else {
    29         double k = - (p2.x - p1.x) / (p2.y - p1.y);
    30         double cx = (p1.x + p2.x) / 2.0;
    31         double cy = (p1.y + p2.y) / 2.0;
    32         double b = cy - k * cx;
    33         line.a = k, line.b = -1, line.c = b;
    34     }
    35     return line;
    36 }
    37 
    38 Point ps[200];
    39 int n = 0, max = 1;
    40 
    41 // count the number of points in the circle whose center is c
    42 int count(Point c) {
    43     int i, ret = 0;
    44     for (i = 0; i < n; i++) {
    45         double dx = ps[i].x - c.x;
    46         double dy = ps[i].y - c.y;
    47         double d = sqrt(dx*dx + dy*dy);
    48         if (d > 2.5) continue; // the radius equals 2.5
    49         ret++;
    50     }
    51     return ret;
    52 }
    53 
    54 int main() {
    55     double x, y; int i, j;
    56     while (scanf("%lf%lf", &x, &y) != EOF) {
    57         ps[n].x = x, ps[n].y = y;
    58         n++;
    59     }
    60     
    61     for (i = 0; i < n; i++) {
    62         for (j = i+1; j < n; j++) {
    63             double dx = ps[j].x - ps[i].x;
    64             double dy = ps[j].y - ps[i].y;
    65             double dd = dx * dx + dy * dy;
    66             int tmp1, tmp2;
    67             if (dd > 25.0) continue;
    68             else if (equal(dd, 25.0)) {
    69                 Point center; 
    70                 center.x = (ps[i].x + ps[j].x) / 2.0;
    71                 center.y = (ps[i].y + ps[j].y) / 2.0;
    72                 tmp1 = count(center);
    73             } else {
    74                 Line line = bisector(ps[i], ps[j]);
    75                 double d = sqrt(6.25 - dd / 4.0);
    76                 double em = sqrt(line.a * line.a + line.b * line.b);
    77                 double ex = line.b / em;    
    78                 double ey = -line.a / em;
    79                 double cx = (ps[i].x + ps[j].x) / 2.0;
    80                 double cy = (ps[i].y + ps[j].y) / 2.0;
    81                 Point center; 
    82                 center.x = cx + d * ex;
    83                 center.y = cy + d * ey;
    84                 tmp1 = count(center);
    85             
    86                 center.x = cx - d * ex;
    87                 center.y = cx - d * ey;
    88                 tmp2 = count(center);
    89             
    90                 tmp1 = tmp1 > tmp2 ? tmp1 : tmp2;
    91             }
    92             max = max < tmp1 ? tmp1 : max;
    93         }
    94     }
    95     printf("%d
    ", max);
    96     return 0;
    97 }
  • 相关阅读:
    navigator
    历史记录跳转
    更改URL
    计数器
    窗口位置和大小
    open用法
    confirm用法
    项目中访问本地node服务跨域问题
    jenkins使用
    基于Vue的SSR
  • 原文地址:https://www.cnblogs.com/william-cheung/p/3641553.html
Copyright © 2011-2022 走看看