Hoodlum1980 (fafa)'s Technological Blog

Languages mainly using and digging: C / CPP, ASM, C#, Python. Other languages:Java.

博客园 首页 新随笔 联系 订阅 管理

    地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1608

    题意:给你两个圆形(半径分别为 r1 、r2 )和一个矩形(矩形边长为 a 和 b),判断两个圆是否能放于矩形内。其中 a, b, r1, r2 都是浮点数。

    分析:考虑两个圆能放入的一个最基本的必要条件就是:半径最大的圆至少要能放入,那么小圆自然也能放入,即 min( a,  b ) >= max( r1, r2 ) * 2;

    接下来分析能否放入的临界点。假设矩形的长边是 a,短边是 b,大圆半径是 r1, 小圆半径是 r2,满足上述条件时( b >= r1 * 2 ),r2 很小的情况可以不必考虑。

    另 b 略大于 r1 * 2,设想右侧短边是一个可以滑动的挡板,从远处向左侧短边滑动。 当 a 非常大时,两个圆靠近成相切状态,两个圆可以同时与底边相切(但这不是最节省空间状态)。当矩形向内收缩时,达到下图所示状态时(两个圆分别和矩形相对的边相切,即理想状态下矩形每条边只和一个圆相切,只有一个切点),将不能继续收缩,即到达临界点:

    

    我们也可以从另一个角度理解,假设上图是一个内壁十分光滑的容器(可以是集装箱或者汽油桶)的截面,底部的宽度固定为 a,且略大于大圆(表面光滑的圆柱体或者球体)直径(2*r1),先把大圆放入容器,再把小圆放入,则必然因为重力作用,小圆把大圆挤向容器的另一侧,稳定于上述图形的状态。

    设图中红色直角三角形的两个直角边边分别为 x,y,斜边为 z,则:

    z = r1 + r2;

    x = a - z;

    y = b - z;

    其中斜边 z 是两圆相切时的圆心距离,可看作是固定的。直角边 x、y 主要取决于矩形边长。因此当 z^2 <= x^2 + y^2 时意味着矩形足够大,可以放入矩形内。否则不能放入。下面的代码中函数 judge 的返回值含义看做是 BOOL 类型,表示是否可放入。

 

zoj1608
#include <math.h>
#include <stdio.h>

int judge(double a, double b, double r1, double r2)
{
    double maxside = a > b ? a : b;
    double minside = a < b ? a : b;
    double maxR = r1 > r2 ? r1 : r2;
    double minR = r1 < r2 ? r1 : r2;

    if(minside < maxR * 2)
        return 0;

    double z = r1 + r2;
    double x = a - z;
    double y = b - z;
    
    if(x * x + y * y < z * z)
        return 0;
    else
        return 1;
}

int main(int argc, char* argv[])
{
    double a, b, r1, r2;
    while(scanf("%lf %lf %lf %lf", &a, &b, &r1, &r2) != EOF)
    {
        if(judge(a, b, r1, r2)) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

 

    最后,题目中的“You can safely assume x < y, where x and y are float-point numbers, if x < y + 0.01.” 这句话是什么意思呢,其实就是让你不必关注浮点数的大小比较,其两个浮点数的大小关系将是非常显著的。我推测出题者的意思就是测试数据的浮点数关系不是大于就是小于(明显不能放入或明显能放入),而不会出现非常接近(非常靠近能否放入的临界点),例如 1.00001 和 1.00002 这样的让人比较纠结的情况。所以上面的代码中不必考虑浮点计算和比较时的精度问题,即分析和代码中的所有等于号“=”应该都是可以去掉的。如果两个浮点数非常接近,例如给出一个矩形的边分别是 5.0000 和 4.9999,满足 5.0000 < (4.9999 + 0.1 ),则导致可以认为 5.0000 < 4.9999,这显然是荒唐的。

 

posted on 2012-06-04 19:29  hoodlum1980  阅读(583)  评论(0编辑  收藏  举报