前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >挑战程序竞赛系列(89):3.6平面扫描(3)

挑战程序竞赛系列(89):3.6平面扫描(3)

作者头像
用户1147447
发布2018-01-02 10:56:37
6440
发布2018-01-02 10:56:37
举报
文章被收录于专栏:机器学习入门

挑战程序竞赛系列(89):3.6平面扫描(3)

传送门:POJ 3292: Rectilinear polygon

题意参考hankcs: http://www.hankcs.com/program/algorithm/poj-3293-rectilinear-polygon.html

题意:

直角多边形:给定N个点,问是否能组成直角多边形(每个顶点都与另外两个顶点构成直角,每条边都平行于坐标轴),并求出周长?

思路参考: http://www.cnblogs.com/ZefengYao/p/7470984.html

平面扫描,按照x轴扫描可以获得所有竖边的长度和,按y轴的同理,先讨论x轴的情况,将点按照x坐标大小排序后,同一列上的点按照y坐标从小到大排序,之后再观察多边形每一列的特性,可以发现每一列上点必定偶数个,相邻两个配对可以成为一条边,若出现奇数条边,肯定是构不成多边形的。按y轴扫描也是相同做法。其次还要判断是否有横竖边相交的情况以及是否有洞(图是否连通)即可。

讲的很清楚了,此题的trick在于如何实现水平线与垂直线的相交判断,记录哪些信息可以检测出相交问题呢?

首先按照x轴扫描,不会出现相交的线,所以只需要把每条线段信息记录在一种数据结构即可,方便y轴扫描时判断相交。显然,给定一条水平线的横坐标的两端,我们只需要比较该区间内是否有垂直线与之相交,采用TreeSet维护x轴垂直线的有序,接着只要在扫描y轴时,知道两个端点,就可以拿到该区间内的垂直线逐个判断即可。

代码如下:

代码语言:javascript
复制
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main{

    String INPUT = "./data/judge/201709/P3293.txt";

    public static void main(String[] args) throws IOException {
        new Main().run();
    }

    static final int MAX_N = 100000 + 16;

    class Point {
        int x;
        int y;
        Point[] nxt;
        int tot;

        Point(int x, int y){
            this.x = x;
            this.y = y;
            this.tot = 0;
            this.nxt = new Point[2];
        }

        void add(Point a) {
            nxt[tot++] = a;
        }

        @Override
        public boolean equals(Object obj) {
            Point p = (Point) obj;
            return p.x == x && p.y == y;
        }

        @Override
        public String toString() {
            return "(" + x + " " + y + ")";
        }
    }

    class Line implements Comparable<Line>{
        int x;
        int y0;
        int y1;

        Point[] ps;

        Line (int x, int y0, int y1){
            this.x = x;
            this.y0 = y0;
            this.y1 = y1;
            ps = new Point[2];
        }

        int distance() {
            int dx = ps[0].x - ps[1].x;
            int dy = ps[0].y - ps[1].y;
            return Math.abs(dx) + Math.abs(dy);
        }

        @Override
        public int compareTo(Line o) {
            return this.x - o.x;
        }

        @Override
        public boolean equals(Object obj) {
            Line o = (Line) obj;
            return o.x == x && o.y0 == y0 && o.y1 == y1;
        }

        @Override
        public String toString() {
            return ps[0].toString() + "->" + ps[1].toString();
        }
    }

    int N;
    Point[] ps;

    boolean intersect(Point a, Point b, Point c, Point d) {  // 左 a 右 b 下 c 上 d
        return a.x < c.x && b.x > c.x && c.y < a.y && d.y > a.y;
    }

    long solve() {

        TreeSet<Line> lines = new TreeSet<Line>();
        long ans = 0;

        Arrays.sort(ps, 0, N, new Comparator<Point>() {

            @Override
            public int compare(Point o1, Point o2) {
                return o1.x != o2.x ? o1.x - o2.x : o1.y - o2.y;
            }
        });

        for (int i = 0; i < N; ++i) {  // 按x轴方向扫描

            int j = i;
            while (j < N && ps[j].x == ps[i].x) ++j;
            if (((j - i) & 1) != 0) return -1;
            else {
                for (int k = i; k < j; k += 2) {
                    ps[k].add(ps[k + 1]);
                    ps[k + 1].add(ps[k]);
                    Line line = new Line(ps[k].x, ps[k].y, ps[k + 1].y);
                    line.ps[0] = ps[k];
                    line.ps[1] = ps[k + 1];
                    ans += line.distance();
                    lines.add(line);
                }
            }
            i = j - 1;
        }

        Arrays.sort(ps, 0, N, new Comparator<Point>() {

            @Override
            public int compare(Point o1, Point o2) {
                return o1.y != o2.y ? o1.y - o2.y : o1.x - o2.x;
            }
        });

        for (int i = 0; i < N; ++i) { //按y轴方向扫描
            int j = i;
            while (j < N && ps[j].y == ps[i].y) ++j;
            if (((j - i) & 1) != 0) return -1;
            else {
                for (int k = i; k < j; k +=2) {
                    ps[k].add(ps[k + 1]);
                    ps[k + 1].add(ps[k]);

                    Line l1 = new Line(ps[k].x, 0, 0);
                    Line l2 = new Line(ps[k + 1].x, 0, 0);
                    l1.ps[0] = ps[k];
                    l1.ps[1] = ps[k + 1];

                    for (Line line : lines.subSet(l1, l2)) {
                        if (intersect(l1.ps[0], l1.ps[1], line.ps[0], line.ps[1])) return -1;
                    }
                    ans += l1.distance();
                }
            }
            i = j - 1;
        }

        Point crt = ps[0];
        Point pre = null;
        int cnt = 0;
        do {
            cnt ++;
            Point tmp = crt;
            if (pre == crt.nxt[0]) {
                crt = crt.nxt[1];
            }
            else{
                crt = crt.nxt[0];
            }
            pre = tmp;
        }
        while (!crt.equals(ps[0]));
        return cnt == N ? ans : -1;
    }

    void read() {
        int T = ni();
        while (T --> 0) {
            N = ni();
            ps= new Point[N];

            for (int i = 0; i < N; ++i) {
                int x = ni();
                int y = ni();
                ps[i] = new Point(x, y);
            }

            out.println(solve());
        }
    }

    FastScanner in;
    PrintWriter out;

    void run() throws IOException {
        boolean oj;
        try {
            oj = ! System.getProperty("user.dir").equals("F:\\java_workspace\\leetcode");
        } catch (Exception e) {
            oj = System.getProperty("ONLINE_JUDGE") != null;
        }

        InputStream is = oj ? System.in : new FileInputStream(new File(INPUT));
        in = new FastScanner(is);
        out = new PrintWriter(System.out);
        long s = System.currentTimeMillis();
        read();
        out.flush();
        if (!oj){
            System.out.println("[" + (System.currentTimeMillis() - s) + "ms]");
        }
    }

    public boolean more(){
        return in.hasNext();
    }

    public int ni(){
        return in.nextInt();
    }

    public long nl(){
        return in.nextLong();
    }

    public double nd(){
        return in.nextDouble();
    }

    public String ns(){
        return in.nextString();
    }

    public char nc(){
        return in.nextChar();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;
        boolean hasNext;

        public FastScanner(InputStream is) throws IOException {
            br = new BufferedReader(new InputStreamReader(is));
            hasNext = true;
        }

        public String nextToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (Exception e) {
                    hasNext = false;
                    return "##";
                }
            }
            return st.nextToken();
        }

        String next = null;
        public boolean hasNext(){
            next = nextToken();
            return hasNext;
        }

        public int nextInt() {
            if (next == null){
                hasNext();
            }
            String more = next;
            next = null;
            return Integer.parseInt(more);
        }

        public long nextLong() {
            if (next == null){
                hasNext();
            }
            String more = next;
            next = null;
            return Long.parseLong(more);
        }

        public double nextDouble() {
            if (next == null){
                hasNext();
            }
            String more = next;
            next = null;
            return Double.parseDouble(more);
        }

        public String nextString(){
            if (next == null){
                hasNext();
            }
            String more = next;
            next = null;
            return more;
        }

        public char nextChar(){
            if (next == null){
                hasNext();
            }
            String more = next;
            next = null;
            return more.charAt(0);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-09-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 挑战程序竞赛系列(89):3.6平面扫描(3)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档