zoukankan      html  css  js  c++  java
  • PAT Top 1011. Cut Rectangles (35)减少讨论的解法

    原题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" << "
    ";
            else
                cout << "NO" << "
    ";
        }
        system("pause");
        return 0;
    }
  • 相关阅读:
    大二暑假学习第一周
    PyQt5+pycharm 中对生成的.py文件无法运行的问题
    尚筹网19总结
    尚筹网19项目部署
    MAC远程连接Linux
    尚筹网17订单、支付
    尚筹网16确认回报、订单
    支付宝沙箱环境
    内网穿透
    支付宝开发平台使用
  • 原文地址:https://www.cnblogs.com/wzj998/p/7441871.html
Copyright © 2011-2022 走看看