为了账号安全,请及时绑定邮箱和手机立即绑定

算法_java_魔王深测器


import java.util.ArrayList;
import java.util.List;

/**
 * 题目来源:https://segmentfault.com/q/1010000000519081
 * 
 * 琼斯博士在寻宝的过程中,来到了一个平面图呈矩形的封闭房间。
 * 
 * 矩形的宽度为w,高度为h。为方便描述,我们将矩形左上角坐标定为(0,0),右下角坐标定为(w,h)。
 * 
 * 房间的入口在矩形上沿的中点(即(w/2,0)),出口在矩形下沿的中点(即(w/2,h))。
 * 狡猾的魔王还旋转了许多红外深测器,一旦进入探测器的探测半径以内,将触发警报。
 * 
 * 现在琼斯博士向您求助,他能否全身而退不惊动魔王?
 * 
 * 输入:boolean escape(int w,int h,int n,double[] x,double[] y,double[] r)
 * 
 * w为矩形宽度,h为矩形高度,n为探测器总数。每i个探测器的坐标为(x[i],y[i]),探测半径为r[i].
 * 
 * 输出:true or false
 * 
 * PS:这题其实没说琼斯博士多胖哈~
 * 
 */
public class Test {
    /** 含有左边界的探测器对象的集合 */
    private static List<Detector> listDetectors = new ArrayList<Detector>();
    /** 当前探测器是否含有左边界 */
    private static boolean nowIsLift = false;
    /** 是否含有右边界探测器 */
    private static boolean isRight = false;
    /** 最终找没找到 */
    private static boolean result;

    /**
     * 解决原理:
     * 
     * 首先转化为图。每个圆是一个节点,左半个迷宫墙壁是个顶点,右半边迷宫墙壁是个顶点(两个墙壁是对称的U型)。
     * 
     * 如果两个圆相交或者相切、或者碰到墙壁就是节点相连。
     * 
     * 如果左半边墙壁和右半边墙壁联通,则返回false,否则true
     */
    public static void main(String[] args) {
        // /*测试用例1:门口就有探测器,惊动魔王*/
        // int w = 40;
        // int h = 40;
        // int n = 4;
        // double[] xArr = new double[] { 30, 20, 10,20 };
        // double[] yArr = new double[] { 10, 20, 30,10 };
        // double[] rArr = new double[] { 11, 10, 9,10 };// 11,10,9则最终为false
        // /* 测试用例2:探测器左边与右边连通的,惊动魔王 */
        // int w = 40;
        // int h = 40;
        // int n = 4;
        // double[] xArr = new double[] { 30, 20, 10, 20 };
        // double[] yArr = new double[] { 10, 20, 30, 10 };
        // double[] rArr = new double[] { 11, 10, 10, 5 };// 11,10,9则最终为false
        /* 测试用例3:探测器左边与右边未连通的,没惊动魔王 */
        int w = 40;
        int h = 40;
        int n = 4;
        double[] xArr = new double[] { 30, 20, 10, 20 };
        double[] yArr = new double[] { 10, 20, 30, 10 };
        double[] rArr = new double[] { 11, 10, 5, 5 };// 11,10,9则最终为false
        /* 调用escape判断是否会惊动魔王 */
        escape(w, h, n, xArr, yArr, rArr);
        /* 打印输出是否会惊动魔王的结果 */
        if (result) {
            System.out.println("惊动了魔王");
        } else {
            System.out.println("没惊动魔王");
        }

    }

    /**
     * 
     * @param w
     *            距形宽度
     * @param h
     *            距形高度
     * @param n
     *            探测器总数
     * @param x
     *            所有探测器的x坐标集合
     * @param y
     *            所有探测器的y坐标集合
     * @param r
     *            所有探测器的半径集合
     * @return true:惊动魔王 false:不惊动魔王
     */
    private static void escape(int w, int h, int n, double[] xArr,
            double[] yArr, double[] rArr) {
        /* 初始化数据 */
        double x;// 探测器的x坐标
        double y;// 探测器的y坐标
        double r;// 探测器的半径r
        List<Detector> detectorLinks = new ArrayList<Detector>();// 与该探测器相连(相交或者相切)的其它探测器集合
        boolean isLeftLink;// 该节点是否与左半边墙壁相连
        boolean isRightLink;// 该节点是否与右半边墙壁相连
        List<Detector> allDetector = new ArrayList<Detector>();// 所有遍历过的探测器
        Detector detector = null;// 临时创建的探测器
        /* 遍历每一个探测器 */
        for (int i = 0; i < n; i++) {
            x = xArr[i];
            y = yArr[i];
            r = rArr[i];
            if (isStartOrEnd(x, y, r, w, h)) {
                result = true;// 门口就是探测器,一定惊动魔王
                return;
            }
            isLeftLink = isLinkFun(x, y, r, 0, w, h);
            isRightLink = isLinkFun(x, y, r, 1, w, h);
            detector = new Detector(x, y, r, detectorLinks, isLeftLink,
                    isRightLink);
            // System.out.println("detector==" + detector.getDetectorLinks());
            if (nowIsLift) {
                listDetectors.add(detector);
            }
            setDetectorLinks(detector, allDetector, x, y, r);
            allDetector.add(detector);// 开始添加探测器
        }
        /* 计算每个有左边界的探测器开始深度遍历 */
        if (isRight) {
            /* 右边界存在开始查找 */
            resultDepthTraverse();
        } else {
            /* 右边界不存在 */
            result = false;
        }
    }

    /**
     * 
     * @param x
     *            当前探测器x坐标
     * @param y
     *            当前探测器y坐标
     * @param r
     *            当前探测器半径r
     * @param w
     *            当前距形宽
     * @param h
     *            当前距形高
     * @return true:包含了 false:没包含
     */
    private static boolean isStartOrEnd(double x, double y, double r, int w,
            int h) {
        if (Math.pow(Math.abs(x - w / 2), 2) + Math.pow(Math.abs(y - 0), 2) <= Math
                .pow(r, 2)) {
            /* 包含上面点了 */
            return true;
        } else if (Math.pow(Math.abs(x - w / 2), 2)
                + Math.pow(Math.abs(y - h), 2) <= Math.pow(r, 2)) {
            /* 包含下面点了 */
            return true;
        }
        return false;
    }

    /**
     * 深度遍历
     * 
     * @return 深度遍历结果
     */
    private static boolean resultDepthTraverse() {
        for (int i = 0; i < listDetectors.size(); i++) {
            Detector detector = listDetectors.get(i);// 每一个含有左边界的圆
            depthTraverse(detector);// 利用递归深度查找,直到找到一个最终的含有右边界的结果时,就不找了
        }
        return false;
    }

    /**
     * 利用递归深度查找,直到找到一个最终的含有右边界的结果时,就不找了
     * 
     * @param detector
     */
    private static void depthTraverse(Detector detector) {
        // System.out.println("==========detector==========");
        // System.out.println("x=" + detector.getX() + ",y=" + detector.getY()
        // + ",r=" + detector.getR());
        if (detector.isTraverse()  result) {
            return;
        }
        detector.setTraverse(true);// 下回这个不遍历了
        List<Detector> detectors = detector.getDetectorLinks();
        for (int i = 0; i < detectors.size(); i++) {
            detector = detectors.get(i);
            if (detector.isRightLink()) {
                // System.out.println("找到了!!!");
                result = true;
            } else {
                depthTraverse(detector);
            }
        }
    }

    /**
     * 遍历已经遍历过的探测器,判断是否与之相连
     * 
     * @param detectorLinks
     *            与该探测器相连(相交或者相切)的其它探测器集合
     * @param allDetector
     *            所有遍历过的探测器
     * @param r
     *            探测器的x坐标
     * @param y
     *            探测器的y坐标
     * @param x
     *            探测器的半径r
     */
    private static void setDetectorLinks(Detector detector,
            List<Detector> allDetector, double x, double y, double r) {
        List<Detector> detectorLinks = detector.getDetectorLinks(); // 当前新建的探测器的子孩子
        Detector allDetectorItem = null;// 每一个曾遍历过的Detector
        for (int i = 0; i < allDetector.size(); i++) {
            allDetectorItem = allDetector.get(i);
            double itemX = allDetectorItem.getX();
            double itemY = allDetectorItem.getY();
            double itemR = allDetectorItem.getR();
            if (Math.pow(Math.abs(itemX - x), 2)
                    + Math.pow(Math.abs(itemY - y), 2) <= Math
                        .pow(itemR + r, 2)) {
                /* 相连 */
                // System.out.println("allDetectorItem= " + allDetectorItem);
                // System.out.println("getDetectorLinks= "
                // + allDetectorItem.getDetectorLinks());
                allDetectorItem.getDetectorLinks().add(detector);// 当前探测器加入可连接探测器
                detectorLinks.add(allDetectorItem);// 可连接探测器加入当前探测器
            } else {
                /* 不相连不处理 */
            }
        }
    }

    /**
     * 是否挨着边界
     * 
     * @param x
     *            当前探测器x坐标
     * @param y
     *            当前探测器y坐标
     * @param r
     *            当前探测器半径r
     * @param direction
     *            0:左 1:右
     * @param w
     *            总的宽度
     * @param h
     *            总的高度
     * @return 返回是否挨着
     */
    private static boolean isLinkFun(double x, double y, double r,
            int direction, int w, int h) {
        if (direction == 0) {
            /* 左边界判断 */
            if (((y - r <= 0  y + r >= h) && x < w / 2)  x - r <= 0) {
                /* 挨着 */
                nowIsLift = true;
                return true;
            } else {
                /* 不挨着,默认执行最后的false */
                nowIsLift = false;
            }
        } else if (direction == 1) {
            /* 右边界判断 */
            if (((y - r <= 0  y + r >= h) && x > w / 2)  x + r >= w) {
                /* 挨着 */
                isRight = true;// 就执行这一次就够了,我只想知道有没有右边界的存在
                return true;
            } else {
                /* 不挨着,默认执行最后的false */
            }
        }
        return false;
    }
}

/**
 * 探测器模型类
 */
class Detector {
    /** 探测器的x坐标 */
    private double x;
    /** 探测器的y坐标 */
    private double y;
    /** 探测器的半径r */
    private double r;
    /** 与该探测器相连(相交或者相切)的其它探测器集合 */
    private List<Detector> detectorLinks;
    /** 该节点是否与左半边墙壁相连 */
    private boolean isLeftLink;
    /** 该节点是否与右半边墙壁相连 */
    private boolean isRightLink;
    /** 当前结点是否被遍历过 */
    private boolean isTraverse = false;

    /**
     * 通过构造方法初始化该探测器的值
     * 
     * @param x
     *            初始化探测器的x坐标
     * @param y
     *            初始化探测器的y坐标
     * @param r
     *            初始化探测器的半径r
     * @param detectorLinks
     *            初始化与该探测器相连(相交或者相切)的其它探测器集合
     * @param isLeftLink
     *            初始化该节点是否与左半边墙壁相连
     * @param isRightLink
     *            初始化该节点是否与右半边墙壁相连
     */
    public Detector(double x, double y, double r, List<Detector> detectorLinks,
            boolean isLeftLink, boolean isRightLink) {
        super();
        this.x = x;
        this.y = y;
        this.r = r;
        this.detectorLinks = detectorLinks;
        this.isLeftLink = isLeftLink;
        this.isRightLink = isRightLink;
    }

    /* ======get、set方法====== */
    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public double getR() {
        return r;
    }

    public boolean isTraverse() {
        return isTraverse;
    }

    public void setTraverse(boolean isTraverse) {
        this.isTraverse = isTraverse;
    }

    public void setR(double r) {
        this.r = r;
    }

    public List<Detector> getDetectorLinks() {
        return detectorLinks;
    }

    public void setDetectorLinks(List<Detector> detectorLinks) {
        this.detectorLinks = detectorLinks;
    }

    public boolean isLeftLink() {
        return isLeftLink;
    }

    public void setLeftLink(boolean isLeftLink) {
        this.isLeftLink = isLeftLink;
    }

    public boolean isRightLink() {
        return isRightLink;
    }

    public void setRightLink(boolean isRightLink) {
        this.isRightLink = isRightLink;
    }

}

图片描述

点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
81
获赞与收藏
11

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消