POJ 2826 An Easy Problem?!

 

题目还行,可惜自己不争气。

一开始就想到了所有情况:

1. 两条线不相交,不能装水。

2. 两条线重合 或 平行 不能装水。

3. 其中一条线水平放置,不能装水。

4. 如下图, 不能装水,同理两直线都向右斜时,也有这种情况

4. 把3中的图稍微改动一下,就能装水了,如下图

可见,先判断是不是1,2,3 这几种情况,如果不是,那么4,5这两种情况要再判断一下。

 

我想,这次不能再看别人的解题报告, 要自己做才能学到许多,尽管自己的方法不是很好,

以下思路纯自己构思,代码纯手写, 写得太乱, 太杂, 尽管做了一下午,每次都是测试了好几组数据才交, 还是16WA,但完全靠自己A了心情就是不一样,爽啊。

通过这题我学会了思考,不要过分依赖别人,当然自己A了以后可以看看别人的做法,这个是很有必要的。

 

我的奇葩AC代码:

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define eps 10e-8

struct point
{
    double x, y;
    point(){}
    point(double xx, double yy) : x(xx), y(yy){};
};

struct seg
{
    point a, b;
    seg(){}
    seg(point aa, point bb) : a(aa), b(bb){};
}s[3];

point p, tmp;
int flag[3];

double cross(point o, point p1, point p2)//叉积
{
    return (p1.x - o.x)*(p2.y - o.y) - (p1.y - o.y)*(p2.x - o.x);
}

bool seg_cross(seg s1, seg s2)//判断线段是否相交 (规范相交 和 不规范相交,不考虑共线)
{
    if(cross(s1.a, s1.b, s2.a) * cross(s1.a, s1.b, s2.b) <= eps
    && cross(s2.a, s2.b, s1.a) * cross(s2.a, s2.b, s1.b) <= eps)
    return 1;
    return 0;
}
point line_cross(seg u,seg v) //两直线求交点(标准模板)
{
    point ret=u.a;
    double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))
            /((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));
    ret.x+=(u.b.x-u.a.x)*t;
    ret.y+=(u.b.y-u.a.y)*t;
    return ret;
}
bool judge(seg s1, seg s2)//判断两线段是否平行
{
    if( (s1.a.y - s1.b.y)*(s2.a.x - s2.b.x) == (s2.a.y - s2.b.y)*(s1.a.x - s1.b.x) ) return 1;
    return 0;
}
int main()
{
    int cas, i, j;
     scanf("%d", &cas);
    while(cas--)
    {
        for(i = 1; i <= 2 ;i++)
            scanf("%lf%lf%lf%lf",&s[i].a.x, &s[i].a.y, &s[i].b.x, &s[i].b.y);
        if(!seg_cross(s[1], s[2]) || s[1].a.y == s[1].b.y || s[2].a.y == s[2].b.y ||judge(s[1], s[2])) //1,2这两种情况
            { printf("0.00\n"); continue;}
         //求两线段交点,并去除交点以下的线段
        p = line_cross(s[1], s[2]);
        for(i = 1; i <= 2; i++)
        {
            if( s[i].a.y < s[i].b.y || s[i].a.y ==  s[i].b.y && s[i].a.x < s[i].b.x ) swap(s[i].a, s[i].b);  //把线段中 点y值大的移到 线段的a端点
            s[i].b = p;    //b端变为交点
        }
        if(s[1].a.y > s[2].a.y )swap(s[1], s[2]); //把线段a端y值大的移到水线段s[1]去
        if( (s[1].a.x - p.x) * (s[1].a.y - p.y) * (s[2].a.x - p.x) * (s[2].a.y - p.y) > -eps)//判断两直线斜率相乘是否大于0,除法和乘法正负性不变,就是4,5的情况和跟4,5对称的情况
        {
            if(seg_cross( seg( s[1].a, point(s[1].a.x, s[2].a.y) ), s[2])) //判断线段a端y值比较小的 线段 向上延长 跟 另一条线段是否相交,相交就说明 上面的板盖住了下面的板, 不能装水 。
                {printf("0.00\n"); continue;}
        }
        // 剩下的情况都可以装水, 根据木桶效应,两个线段的高度应该取 两个之中最低的
        if(s[1].a.y > s[2].a.y) s[1].a = line_cross( s[1], seg( point(0, s[2].a.y), point(1, s[2].a.y)) );
        else if(s[1].a.y < s[2].a.y) s[2].a = line_cross( s[2], seg( point(0, s[1].a.y), point(1, s[1].a.y)) );
        //计算面积
        printf("%.2f\n", (s[1].a.y - p.y) * fabs((s[1].a.x - s[2].a.x))/2);

    }
    return 0;
}

 

 

posted @ 2012-08-18 17:15  To be an ACMan  Views(269)  Comments(0)    收藏  举报