挑战程序竞赛系列(86):3.6极限情况(3)

来源:互联网 发布:加工中心编程实例讲解 编辑:程序博客网 时间:2024/06/02 04:56

挑战程序竞赛系列(86):3.6极限情况(3)

传送门:AOJ 2201: Immortal Jewels


翻译参考至hankcs:
http://www.hankcs.com/program/algorithm/aoj-2201-immortal-jewels.html

题意:

求婚:有个贵族向一个贫穷的公主求婚,公主提出条件,需要一种“永生宝石”做嫁妆。这种宝石极其稀有,而且极易损毁,所以开采时需要特别小心。如图:
alt text
矿工需要使用一种特殊的金属棒开采,宝石呈圆形,矿床是二维平面,每颗宝石坐标为x,y,半径为r,能够吸附在距离m内的金属棒上。一旦金属棒穿过某个宝石,该宝石就被破坏了。
alt text
金属棒非常昂贵,只有一根,作为贵族雇佣的程序员,请你帮他算出能开采到的最大宝石数?
数据格式如下:
N
x1 y1 r1 m1
x2 y2 r2 m2

xN yN rN mN
由多个用例组成,输出答案并换行。

直接参考hankcs:

对每个宝石圆,都添加半径扩大m_i的磁力范围圆,将两个圆同时纳入考虑,移动直线的过程中,如果能取到的宝石个数发生变化,那么直线肯定与所有圆中的两个相切,这就是极限情况。所以枚举两个圆的组合确定一条直线,取最大值就行了。

此题的麻烦之处在于求解两个圆的外接切线和内接切线,具体直接参考代码吧。

代码如下:

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.ArrayList;import java.util.List;import java.util.StringTokenizer;public class Main{    String INPUT = "./data/judge/201709/A2201.txt";    public static void main(String[] args) throws IOException {        new Main().run();    }    static final double PI  = Math.acos(-1);    static final double EPS = 1E-12;    class Point{        double x;        double y;        Point(double x, double y){            this.x = x;            this.y = y;        }        Point add(Point a) {            return new Point(x + a.x, y + a.y);        }        Point sub(Point a) {            return new Point(x - a.x, y - a.y);        }        Point rot(double rad) {            double a = Math.cos(rad);            double b = Math.sin(rad);            return new Point(x * a - b * y, x * b + a * y);        }        double abs() {            return Math.sqrt(x * x + y * y);        }    }    double dist(Point a, Point b) {        double dx = a.x - b.x;        double dy = a.y - b.y;        return Math.sqrt(dx * dx + dy * dy);    }    double dot(Point a, Point b) {        return a.x * b.y - a.y * b.x;    }    class Line{        Point a;        Point b;        Line(Point a, Point b){            this.a = a;            this.b = b;        }        double distance(Point p) {            double d = dist(a, b);            return Math.abs(dot(p.sub(a), b.sub(a)) / d);        }    }    class Circle{        Point o;        double r;        Circle(Point o, double r){            this.o = o;            this.r = r;        }        // 通过点p 的两条切线        List<Point> tangent(Point p){            double L = dist(o, p);            double M = Math.sqrt(L * L - r * r);            double theta = Math.asin(r / L);            Point v = o.sub(p);            v.x /= L;            v.y /= L;            List<Point> ans = new ArrayList<>();            Point t = v.rot(theta);            t.x *= M;            t.y *= M;            ans.add(p.add(t));            t = v.rot(-theta);            t.x *= M;            t.y *= M;            ans.add(p.add(t));            return ans;        }        // 两个半径相等圆的两条平行外切线        List<Line> outer_tangent_parallel(Circle c){            Point d = o.sub(c.o);            Point v = new Point(-r / d.abs() * d.y, r / d.abs() * d.x);            List<Line> lines = new ArrayList<>();            lines.add(new Line(o.add(v), c.o.add(v)));            lines.add(new Line(o.sub(v), c.o.sub(v)));            return lines;        }        // 两圆外切线        List<Line> outer_tangent(Circle c){            if (cmp(r, c.r) == 0) {                return outer_tangent_parallel(c);            }            if (cmp(r, c.r) == 1) {                return c.outer_tangent(this);            }            Point d = o.sub(c.o);            double fact = c.r / r - 1;            Point base = c.o.add(d).add(new Point(d.x / fact, d.y / fact));            List<Point> ps = tangent(base);            List<Line> ans = new ArrayList<>();            ans.add(new Line(base, ps.get(0)));            ans.add(new Line(base, ps.get(1)));            return ans;        }        // 两圆内切线        List<Line> inner_tangent(Circle c){            if (cmp(r, c.r) == 1) {                return c.inner_tangent(this);            }            Point d = c.o.sub(o);            double fact = c.r / r + 1;            Point base = o.add(new Point(d.x / fact, d.y / fact));            List<Point> ps = tangent(base);            List<Line> ans = new ArrayList<>();            ans.add(new Line(base, ps.get(0)));            ans.add(new Line(base, ps.get(1)));            return ans;        }        // 两个圆的交点        Line intersection(Circle c) {            double d = dist(o, c.o);            double cos = Math.cos((d * d + r * r - c.r * c.r) / (2 * d * r));            Point e = c.o.sub(o);            e.x /= d;            e.y /= d;            Point t1 = e.rot(cos);            t1.x *= r;            t1.y *= r;            Point t2 = e.rot(-cos);            t2.x *= r;            t2.y *= r;            return new Line(o.add(t1), o.add(t2));        }        // 是否相离        boolean independent(Circle c) {            return cmp(dist(o, c.o), r + c.r) > 0;        }        // 是否包含圆c        boolean contains(Circle c) {            return cmp(dist(o, c.o) + c.r, r) < 0;        }        boolean intersects(Circle c) {            return !contains(c) && !c.contains(this) && !independent(c);        }    }    class Pair{        Circle fir;        Circle sec;        Pair(Circle fir, Circle sec){            this.fir = fir;            this.sec = sec;        }    }    int cmp(double a, double b) {        double diff = a - b;        if (Math.abs(diff) < EPS) return 0;        else if (diff < 0) return -1;        else return 1;    }    List<Pair> jewels;    List<Line> lines;    int N;    void constructLine(Circle c1, Circle c2, List<Line> lines) {        // 两圆相交 && 两圆相离        if (c1.independent(c2)) { // 相离            List<Line> outer = c1.outer_tangent(c2);            lines.add(outer.get(0));            lines.add(outer.get(1));            List<Line> inner = c1.inner_tangent(c2);            lines.add(inner.get(0));            lines.add(inner.get(1));        }        if (c1.intersects(c2)) {  // 相交            List<Line> outer = c1.outer_tangent(c2);            lines.add(outer.get(0));            lines.add(outer.get(1));            Line inter = c1.intersection(c2);            lines.add(inter);        }    }    int count(List<Pair> jewels, Line line) {        int cnt = 0;        for (Pair j : jewels) {            if (cmp(j.fir.r, line.distance(j.fir.o)) <= 0 && cmp(j.sec.r, line.distance(j.sec.o)) >= 0) {                cnt ++;            }        }        return cnt;    }    void read() {        while (true) {            N = ni();            if (N == 0) break;            jewels = new ArrayList<>();            lines  = new ArrayList<>();            for (int i = 0; i < N; ++i) {                double x, y, r, m;                x = nd();                y = nd();                r = nd();                m = nd();                Pair jewel = new Pair(new Circle(new Point(x, y), r), new Circle(new Point(x, y), r + m));                for (Pair p : jewels) {                    constructLine(jewel.fir, p.fir, lines);                    constructLine(jewel.fir, p.sec, lines);                    constructLine(jewel.sec, p.fir, lines);                    constructLine(jewel.sec, p.sec, lines);                }                jewels.add(jewel);            }            int ans = 1;            for (Line line : lines) {                ans = Math.max(ans, count(jewels, line));            }            out.println(ans);        }    }    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);        }    }}

Java的确没有C++方便,少了操作符重载和Pair只能靠自己写函数,显得代码很冗长。

alt text

阅读全文
0 0
原创粉丝点击