HDU 5128

Link:click here
The question:在平面上给出n(4 <= n <= 30)个点,从中选出8个点够成两个矩形,使得矩形的面积最大,如果不存在,输出”imp”。
Solution:枚举所有的矩形,求出最大值。先将所有矩形的对角线存起来,然后枚举对角线,计算出矩形的坐标,再判断矩形是否存在和矩形的位置关系。 判断矩形相交时,先判断两个矩形成”回”字形的情况,再判断成”十”字的情况,再判断一般相交的情况。因为”回”字形的两个矩形的对角线也可能相交。
Conclusion:两个矩形成”回”字形的情况下,计算大矩形的面积。计算几何中判断位置关系时,会出现多种情况,而且判断位置关系的先后顺序必须正确,考虑的情况必须全面。
Code:

#include <bits/stdc++.h>
using namespace std;
struct Point {
    int x, y;
    Point(int x = -1, int y = -1): x(x), y(y) {}
};
#define Vector Point
struct Line
{
    Point a, b;
    Line() {}
    Line(Point a, Point b): a(a), b(b) {}
} line[1000];
Vector operator + (const Vector& A, const Vector& B) {
    return Vector(A.x + B.x, A.y + B.y);
}
Vector operator - (const Point& A, const Point& B) {
    return Vector(A.x - B.x, A.y - B.y);
}
Vector operator * (const Vector& A, const int& p) {
    return Vector(A.x * p, A.y * p);
}
Vector operator / (const Vector& A, const int& p) {
    return Vector(A.x / p, A.y / p);
}
bool operator == (const Point& A, const Point& B) {
    return A.x - B.x == 0 && A.y - B.y == 0;
}
bool operator < (const Point& A, const Point& B) {
    return A.x < B.x || (A.x == B.x && A.y < B.y);
}
int Dot(const Vector& A, const Vector& B) {
    return A.x * B.x + A.y * B.y;
}
int Cross(const Vector& A, const Vector& B) {
    return A.x * B.y - A.y * B.x;
}
//点在线段上的判定
bool isOnSegment(const Point& P, const Point& A, const Point& B) {
    if (P == A || P == B)
        return true;
    return Cross(A - P, B - P) == 0 && Dot(A - P, B - P) < 0;
}
//线段相交判定
bool SegmentProperIntersection(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {
    if (isOnSegment(a1, b1, b2) || isOnSegment(a2, b1, b2) || isOnSegment(b1, a1, a2) || isOnSegment(b2, a1, a2))
        return true;
    int c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
    int c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
    return c1 * c2 < 0 && c3 * c4 < 0;
}
bool cmp(Point A, Point B)
{
    if (A.x != B.x)
        return A.x < B.x;
    return A.y < B.y;
}
int area(Point a, Point b, Point c, Point d)//计算矩形面积
{
    int x = b.y - a.y;
    int y = c.x - a.x;
    return x * y;
}
Point node[33];
int main()
{
    int n;
    while (scanf("%d", &n), n)
    {
        int flag[222][222] = {0};
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d", &node[i].x, &node[i].y);
            flag[node[i].x][node[i].y] = 1;//标记
        }
        if (n < 8)//不能构成两个矩形
        {
            printf("imp\n");
            continue;
        }
        int dex = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = i + 1; j < n; j++)
            {
                if (node[i].x < node[j].x && node[i].y < node[j].y)//将所有对角线存起来,枚举对角线即可
                {
                    line[dex++] = Line(node[i], node[j]);
                }
            }
        }
        Line L1, L2;//矩形1和矩形2的对角线
        Point rec1[4], rec2[4];//枚举出来的矩形1和矩形2
        int ans = -1;
        for (int i = 0; i < dex; i++)//枚举所有对角线
        {
            for (int I = i + 1; I < dex; I++)
            {
                int F = 0;
                L1 = line[i];
                L2 = line[I];
                rec1[0] = L1.a;
                rec1[1] = L1.b;
                rec1[2] = Point(L1.b.x, L1.a.y);
                rec1[3] = Point(L1.a.x, L1.b.y);
                rec2[0] = L2.a;
                rec2[1] = L2.b;
                rec2[2] = Point(L2.b.x, L2.a.y);
                rec2[3] = Point(L2.a.x, L2.b.y);
                sort(rec1, rec1 + 4, cmp);//排序
                sort(rec2, rec2 + 4, cmp);
                for (int j = 0; j < 4 && !F; j++)//判断,矩形是否存在,两个矩形是否有重合的点
                {
                    if (flag[rec2[j].x][rec2[j].y] == 0)
                    {
                        F = 1;
                    }
                    if (flag[rec1[j].x][rec1[j].y] == 0)
                    {
                        F = 1;
                    }
                    for (int k = 0; k < 4 && !F; k++)
                    {
                        if (rec1[j] == rec2[k])
                        {
                            F = 1;
                        }
                    }
                }
                if (F)
                    continue;
                if (rec2[0].x > rec1[0].x && rec2[0].y > rec1[0].y)//如果矩形2包含在矩形1内
                {
                    if (rec2[1].x > rec1[1].x && rec2[1].y < rec1[1].y)
                    {
                        if (rec2[2].x < rec1[2].x && rec2[2].y > rec1[2].y)
                        {
                            if (rec2[3].x < rec1[3].x && rec2[3].y < rec1[3].y)
                            {
                                int x = area(rec1[0], rec1[1], rec1[2], rec1[3]);//计算矩形1的面积
                                ans = max(ans, x);
                                continue;
                            }
                        }
                    }
                }
                if (rec1[0].x > rec2[0].x && rec1[0].y > rec2[0].y)//如果矩形1包含在矩形2内
                {
                    if (rec1[1].x > rec2[1].x && rec1[1].y < rec2[1].y)
                    {
                        if (rec1[2].x < rec2[2].x && rec1[2].y > rec2[2].y)
                        {
                            if (rec1[3].x < rec2[3].x && rec1[3].y < rec2[3].y)
                            {
                                int y = area(rec2[0], rec2[1], rec2[2], rec2[3]);//计算矩形2的面积
                                ans = max(ans, y);
                                continue;
                            }
                        }
                    }
                }
                if (SegmentProperIntersection(L1.a, L1.b, L2.a, L2.b) == true)//对角线相交
                {
                    continue;
                }
                bool fg = false;
                for (int j = 0; j < 4 && !fg; j++)//判断,如果矩形1有一个点在矩形2上,如果矩形1有一个点在矩形2内
                {
                    if (isOnSegment(rec1[j], rec2[0], rec2[1]))
                        fg = true;
                    if (isOnSegment(rec1[j], rec2[0], rec2[2]))
                        fg = true;
                    if (isOnSegment(rec1[j], rec2[1], rec2[3]))
                        fg = true;
                    if (isOnSegment(rec1[j], rec2[2], rec2[3]))
                        fg = true;
                    int t1 = abs(Cross(rec2[0] - rec1[j], rec2[1] - rec1[j]));
                    int t2 = abs(Cross(rec2[1] - rec1[j], rec2[3] - rec1[j]));
                    int t3 = abs(Cross(rec2[2] - rec1[j], rec2[3] - rec1[j]));
                    int t4 = abs(Cross(rec2[0] - rec1[j], rec2[2] - rec1[j]));
                    int t = 2 * area(rec2[0], rec2[1], rec2[2], rec2[3]);
                    if (t1 + t2 + t3 + t4 == t)
                    {
                        fg = true;
                    }
                }
                if (fg)
                    continue;
                fg = false;
                for (int j = 0; j < 4 && !fg; j++)//判断,如果矩形2有一个点在矩形1上,如果矩形2有一个点在矩形1内
                {
                    if (isOnSegment(rec2[j], rec1[0], rec1[1]))
                        fg = true;
                    if (isOnSegment(rec2[j], rec1[0], rec1[2]))
                        fg = true;
                    if (isOnSegment(rec2[j], rec1[1], rec1[3]))
                        fg = true;
                    if (isOnSegment(rec2[j], rec1[2], rec1[3]))
                        fg = true;
                    int t1 = abs(Cross(rec1[0] - rec2[j], rec1[1] - rec2[j]));
                    int t2 = abs(Cross(rec1[1] - rec2[j], rec1[3] - rec2[j]));
                    int t3 = abs(Cross(rec1[2] - rec2[j], rec1[3] - rec2[j]));
                    int t4 = abs(Cross(rec1[0] - rec2[j], rec1[2] - rec2[j]));
                    int t = 2 * area(rec1[0], rec1[1], rec1[2], rec1[3]);
                    if (t1 + t2 + t3 + t4 == t)
                    {
                        fg = true;
                    }
                }
                if (fg)
                    continue;
                int x = area(rec1[0], rec1[1], rec1[2], rec1[3]);
                int y = area(rec2[0], rec2[1], rec2[2], rec2[3]);
                ans = max(ans, x + y);//面积和最大
            }
        }
        if (ans == -1)
        {
            puts("imp");
        }
        else
        {
            printf("%d\n", ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值