# 挑战程序竞赛系列（86）：3.6极限情况（3）

## 挑战程序竞赛系列（86）：3.6极限情况（3）

```import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
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;
}

return new Point(x + a.x, y + a.y);
}

Point sub(Point a) {
return new Point(x - a.x, y - a.y);
}

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;
t = v.rot(-theta);
t.x *= M;
t.y *= M;
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<>();
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;
List<Point> ps = tangent(base);
List<Line> ans = new ArrayList<>();
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<>();
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;
}

// 是否相离
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);
List<Line> inner = c1.inner_tangent(c2);
}

if (c1.intersects(c2)) {  // 相交
List<Line> outer = c1.outer_tangent(c2);
Line inter = c1.intersection(c2);
}
}

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;
}

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);
}
}

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();
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 {
StringTokenizer st;
boolean hasNext;

public FastScanner(InputStream is) throws IOException {
hasNext = true;
}

public String nextToken() {
while (st == null || !st.hasMoreTokens()) {
try {
} 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只能靠自己写函数，显得代码很冗长。

0 条评论

## 相关文章

1212

### 洛谷 P1598 垂直柱状图【字符串+模拟】

P1598 垂直柱状图 题目描述 写一个程序从输入文件中去读取四行大写字母（全都是大写的，每行不超过72个字符），然后用柱状图输出每个字符在输入文件中出现的次数...

3165

3927

### C# String.Format的格式限定符与Format方法将多个对象格式化一个字符串原理

Format方法将多个对象格式化成一个字符串Format方法解析格式字符串的原理:

1252

2735

1203

### 2431: [HAOI2009]逆序对数列

2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 954  Solv...

2936

### 房上的猫：人机猜拳项目

1.首先定义成员变量： int select1;// 人 选择 int select2;// 角色 选择 String choice1;...

3667

### 《Kotlin极简教程》第五章 Kotlin面向对象编程（OOP）一个OOP版本的HelloWorld构造函数传参Data Class定义接口&实现之写pojo bean定一个Rectangle对象封

We frequently create a class to do nothing but hold data. In such a class some s...

2344

1896