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;
}