原题https://www.patest.cn/contests/pat-t-practise/1011:

Sample Input:

8
3 0 0 1 0 1 1
3 0 0 1 1 0 1
3 0 0 1 0 1 1
3 0 0 1 1 0 2
4 0 4 1 4 1 0 0 0
4 4 0 4 1 0 1 0 0
3 0 0 1 1 0 1
4 2 3 1 4 1 7 2 7
5 10 10 10 12 12 12 14 11 14 10
3 28 35 29 35 29 37
3 7 9 8 11 8 9
5 87 26 92 26 92 23 90 22 87 22
5 0 0 2 0 1 1 1 2 0 2
4 0 0 1 1 2 1 2 0
4 0 0 0 1 1 1 2 0
4 0 0 0 1 1 1 2 0

Sample Output:

YES
NO
YES
YES
YES
YES
NO
YES

题目大意说的就是给了两个可能经过90度倍数旋转、镜像、平移的多边形,判断它们是否是由一个垂直于坐标轴的矩形用一条直线切分而成的。

此题有两种思路:

1.枚举旋转、镜像情况,找出两个多边形两条平行且相等的边作为公共边,“焊接”为一个新的多边形,再判断这个多边形是否为矩形且垂直于坐标轴

2.进行分类讨论,有三角形+三角形,三角形+四边形,三角形+五边形,四边形+四边形几种情况

我所用的当然是第一种做法,避免了这些分支情况。

这种做法的难点主要是焊接的过程,需要删去3点共线的中间点,并且一开始最好能把凹多边形的情况排除,再根据一定的顶点时针顺序规则,就可以防止焊接时两个多边形相交的情况。

简单的示意图:

 

图1:三点共线,需要剔除中间这个,方便后续的矩形判断

 

图2:我们不希望看到的情况,B平移为B',与A相交

 

 

图3:正常情况

 

虽然搜了各种情况,效率还是可以的

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
#include <vector>
#include<string>
#include <algorithm>
using namespace std;
class Vector2D {
public:
    Vector2D() {
    }
    void rotate(int angle) {//点绕(0,0)旋转
        long long x0 = x; long long y0 = y;
        if (angle == 0) {
        }
        else if (angle == 90) {
            x = -y0; y = x0;
        }
        else if (angle == 180)
        {
            x = -x0; y = -y0;
        }
        else if (angle == 270)
        {
            x = y0; y = -x0;
        }
    }
    Vector2D(long long x, long long y) {
        this->x = x;
        this->y = y;
    }
    
    long long x = 0;
    long long y = 0;
    bool parrallel2axis() {//向量是否垂直于坐标轴
        if (x == 0 || y == 0) {
            return true;
        }
        return false;
    }
    static long long chaji(Vector2D a, Vector2D b) {//叉积
        return a.x*b.y - b.x*a.y;
    }
    static bool is_shun_clock(Vector2D p1, Vector2D p2, Vector2D p3) {//三点是否符合顺时针
        Vector2D a = p1 - p2;
        Vector2D b = p2 - p3;
        if (chaji(a, b)<0) {
            return true;
        }
        return false;
    }
    Vector2D operator-(Vector2D b) {
        return Vector2D(x - b.x, y - b.y);
    }
    Vector2D operator+(Vector2D b) {
        return Vector2D(x + b.x, y + b.y);
    }
    bool operator==(Vector2D v) {
        if (x == v.x&&y == v.y) {
            return true;
        }
        return false;
    }
    long long operator*(Vector2D b) {//点积
        return x*b.x + y*b.y;
    }
    long long length_square() {//长度的平方
        return x*x + y*y;
    }
};
class Polygon {
public:
    vector<Vector2D> points;
    //输入处理后都用顺时针存放
    Vector2D vct_edg(int i) {//取第i条边到下一条边的向量
        return Vector2D(points[(i + 1) % points.size()] - points[i]);
    }
    void get_all_edge_lengthsquare(vector<long long>& edges_lengthsquare) {
        int n = points.size();
        edges_lengthsquare.resize(n);
        for (int i = 0; i < n; i++) {
            Vector2D now_vct = points[(i + 1) % n] - points[i];
            edges_lengthsquare[i] = (now_vct.length_square());
        }
    }
    static bool all_the_same(vector<long long>& a, vector<long long>& b, int n) {
        for (int i = 0; i < n; i++) {
            if (a[i] != b[i]) {
                return false;
            }
        }
        return true;
    }
    void find_zhijiaos_point_index(vector<Vector2D>& ans_points) {
        //获取多边形中的所有直角角点
        ans_points.resize(0);
        int n = points.size();
        for (int i = 0; i < n; i++) {
            Vector2D& p1 = points[(i - 1 + n) % n];
            Vector2D& p2 = points[i];
            Vector2D& p3 = points[(i + 1) % n];
            if ((p2 - p1)*(p3 - p2) == 0) {
                ans_points.push_back(p2);
            }

        }
    }
    
    void try_invert2clock() {//尝试把点弄成顺时针顺序
                             //处理后并不确保一定不是凹多边形
        if (Vector2D::is_shun_clock(points[0], points[1], points[2])) {

        }
        else {
            vector<Vector2D> points_ = points;
            for (int i = 0; i < points.size(); i++) {
                points[i] = points_[points.size() - 1 - i];
            }
        }
    }
    int next_point(int i) {//某点的顺时针下一点
        return (i + 1) % points.size();
    }
    int last_point(int i) {//某点的顺时针下一点(逆时针下一点)
        return (i - 1 + points.size()) % points.size();
    }
    bool check_shunshizhen() {
        //如果不是所有点满足顺时针return false;
        for (int i = 0; i < points.size(); i++) {
            if (!Vector2D::is_shun_clock(points[last_point(i)], points[i], points[next_point(i)])) {
                return false;
            }
        }
        return true;
    }
    void mirror_me() {//随便哪条轴都是镜像,反正后面要旋转,坐标不重要反正要平移
        for (int i = 0; i < points.size(); i++) {
            points[i].x = -points[i].x;
        }
        try_invert2clock();//镜像操作会导致不是顺时针,要弄回来
    }
    void rotate_me(int angle) {
        for (int i = 0; i < points.size(); i++) {
            points[i].rotate(angle);
        }
    }
    int insert_point(Vector2D& p, int index_b4) {//index_b4是指插在那个点后面(顺时针的下一位)
                                                 
        int index_maybe = next_point(index_b4);

        points.insert(points.begin() + index_maybe, p);
        int index_return = index_maybe;

        return index_return;
    }
    void trans_me(Vector2D vct_trans) {
        for (int i = 0; i < points.size(); i++) {
            points[i] = points[i] + vct_trans;
        }
    }
    bool three_point_in_line(Vector2D& a, Vector2D& b, Vector2D& c) {//三点是否共线
        if (Vector2D::chaji(b - a, c - b) == 0) {
            //用叉积判断其实不能确保b是加在a,c之间的,不过之前排除了凹多边形的情况了
            return true;
        }
        return false;
    }
    void delete_extra_points() {//删除由于共线多余的点
        vector<bool> point_2_delete(points.size(), false);
        for (int i = 0; i < points.size(); i++) {
            int i_b4 = last_point(i); int i_next = next_point(i);
            Vector2D p = points[i]; Vector2D p_b4 = points[i_b4]; Vector2D p_next = points[i_next];//按理说不会出现p不在中间却共线,因为都是凸的
            if (three_point_in_line(p_b4, p, p_next)) {
                point_2_delete[i] = true;
            }
        }
        vector<Vector2D> points_new;
        for (int i = 0; i < points.size(); i++) {
            if (point_2_delete[i]) {
            }
            else {
                points_new.push_back(points[i]);
            }
        }
        points = points_new;
    }
    static Polygon try_combine(Polygon a, int i_a, Polygon b, int i_b) {
        //给定两个多边形以及它们各自公共边起点下标,拼接成一个新的多边形
        int i_a_next = a.next_point(i_a); int i_b_next = b.next_point(i_b);
        Vector2D vct_trans = a.points[i_a] - b.points[i_b_next];
        b.trans_me(vct_trans);
        Polygon& ans = a;
        int p2insert = b.next_point(i_b_next);
        int index_b4 = i_a;
        while (p2insert != i_b)
        {
            index_b4 = ans.insert_point(b.points[p2insert], index_b4);
            p2insert = b.next_point(p2insert);
        }
        ans.delete_extra_points();
        return ans;
    }
    static bool can_combine(Polygon& a, Polygon& b) {
        if (!a.check_shunshizhen() || !b.check_shunshizhen()) {
            return false;
        }
        for (int jx = 0; jx < 2; jx++) {//是否镜像枚举
            Polygon a_jx = a; Polygon b_jx = b;
            if (jx == 1) {
                b_jx.mirror_me();
            }
            for (int anglenow = 0; anglenow < 360; anglenow += 90) {//旋转角度枚举
                Polygon a_jx_rot = a_jx;
                Polygon b_jx_rot = b_jx;
                b_jx_rot.rotate_me(anglenow);
                for (int i_a = 0; i_a < a_jx_rot.points.size(); i_a++) {
                    Vector2D& pa1 = a_jx_rot.points[i_a];
                    Vector2D& pa2 = a_jx_rot.points[a_jx_rot.next_point(i_a)];
                    for (int i_b = 0; i_b < b_jx_rot.points.size(); i_b++) {
                        Vector2D& pb1 = b_jx_rot.points[i_b];
                        Vector2D& pb2 = b_jx_rot.points[b_jx_rot.next_point(i_b)];
                        if ((pa2 - pa1) == (pb1 - pb2)) {
                            //这里要注意后面是pb1 - pb2,与a要反一反,
                            //恰好确保了两个多边形相背而不会相交
                            Polygon ans_now = try_combine(a_jx_rot, i_a, b_jx_rot, i_b);
                            if (ans_now.is_rect()) {
                                if (ans_now.vct_edg(0).parrallel2axis())
                                    return true;
                            }
                        }
                    }
                }

            }
        }
        return false;
    }
    
    bool is_rect() {//是不是矩形
        vector<Vector2D> zhijiao_points;
        find_zhijiaos_point_index(zhijiao_points);
        if (zhijiao_points.size() == 4 && points.size() == 4) {
            return true;
        }
        return false;
    }
};
void myinput(int& n, vector<Polygon>& polys) {
    cin >> n;
    polys.resize(2 * n);
    int k = 0;
    long long xnow = 0, ynow = 0;
    for (int i = 0; i < 2 * n; i++) {
        cin >> k;
        Polygon& poly = polys[i];
        poly.points.resize(k);
        for (int j = 0; j < k; j++) {
            cin >> xnow >> ynow;
            poly.points[j] = Vector2D(xnow, ynow);
        }
        poly.try_invert2clock();
    }
}
int main() {
    vector<Polygon> polys;
    int n = 0;
    myinput(n, polys);
    for (int i = 0; i < n; i++) {
        Polygon& p1 = polys[2 * i]; Polygon& p2 = polys[2 * i + 1];
        if (Polygon::can_combine(p1, p2))
            cout << "YES" << "\n";
        else
            cout << "NO" << "\n";
    }
    system("pause");
    return 0;
}