Description

The famous Ghost Busters team has decided to upgrade their Ectomobile (aka Ecto-1) with a powerful proton gun and an advanced targeting system. Egon has designed and built all the hardware which consists of ectoplasmic scanner and a proton gun that has two degrees of freedom and can automatically rotate and fire in a 90 degrees trihedral angle. You have been hired to write a prototype for the targeting software.

Ghosts are detected by ectoplasmic scanner and are represented as floating spheres. The coordinates of their centers and radii are delivered from the ectoplasmic scanner to the targeting software. The coordinate system is aligned is such a way, that the proton gun fires from the point (0, 0, 0) anywhere into X ≥ 0, Y ≥ 0, Z ≥ 0 trihedral angle. The gun fires a proton ray in a straight line and is so powerful, that even a touch of its ray is enough to kill a ghost. The ray of the proton gun is able to kill a virtually unlimited number of ghosts on its way.

For the first prototype for the targeting software, you are asked to write a program that determines the maximal number of ghosts that can be killed with a single shot of the proton gun.

Input

On the first line of the input there is a single integer number N (0 ≤ N ≤ 100) - the number of ghosts detected by the ectoplasmic scanner of Ecto-1. The following N lines describe detected ghosts - one ghost per line. The description of ith ghost (ghosts are numbered from 1 to N) consists of 4 integer numbers Xi, Yi, Zi, and Ri, separated by spaces. Xi, Yi, Zi (1 ≤ Xi, Yi, Zi ≤ 10000) are the coordinates of the ghost's center, and Ri (1 ≤ Ri ≤ min(Xi, Yi, Zi)) is the ghost's radius. Because ghosts are ectoplasmic, they can be arbitrarily placed in respect to each others. They can intersect, fit inside each other, coincide with each other, etc.

Output

On the first line of the output write a single integer number - the maximal number of ghosts that can be killed with a single shot of the proton gun. On the second line of the output file write the identifying numbers of the ghosts to be killed in an arbitrary order separated by spaces. If there are multiple ways to kill this number of ghosts then write any one.
 
题目大意:在(x≥0,y≥0,z≥0)的空间直角坐标系上有N个球,问从原点发出一条射线,问最多可以穿过多少个球(接触球的边缘也算),输出任意一组穿过的球。
思路:从原点出发的射线要能穿过两个球,那么,我们从原点看过去,这两个球应该是相交的,但是实际上却不一定相交。
那么,我们可以把球缩放到离原点相同的距离上,令看上去相交的球实际上也相交。
然后,枚举所有射线可能的方向,判断这个射线穿过了多少个球。
枚举的方向分别为:所有球的球心、从原点看过去的这些球的交点(射线的方向应该可以选择一个多个圆的交,那么它的每个顶点应该是由圆的交点所组成的)。
 
代码(172MS):
 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL; const double EPS = 1e-;
const double INF = 1e50;
const double PI = acos(-1.0); inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} inline double zero(double x) {
if(sgn(x) == ) return ;
else return x;
} inline double sqr(double x) {
return x * x;
} struct Point3D {
double x, y, z;
Point3D() {}
Point3D(double x, double y, double z): x(x), y(y), z(z) {}
void read() {
scanf("%lf%lf%lf", &x, &y, &z);
}
double operator * (const Point3D &rhs) const {
return x * rhs.x + y * rhs.y + z * rhs.z;
}
Point3D operator + (const Point3D &rhs) const {
return Point3D(x + rhs.x, y + rhs.y, z + rhs.z);
}
Point3D operator - (const Point3D &rhs) const {
return Point3D(x - rhs.x, y - rhs.y, z - rhs.z);
}
Point3D operator * (double rhs) const {
return Point3D(x * rhs, y * rhs, z * rhs);
}
Point3D operator / (double rhs) const {
return Point3D(x / rhs, y / rhs, z / rhs);
}
bool operator == (const Point3D &rhs) const {
return sgn(x - rhs.x) == && sgn(y - rhs.y) == && sgn(z - rhs.z) == ;
}
double length() const {
return sqrt(x * x + y * y + z * z);
}
Point3D unit() const {
return *this / length();
}
}; struct Line3D {
Point3D st, ed;
Line3D() {}
Line3D(Point3D st, Point3D ed): st(st), ed(ed) {}
}; struct Plane3D {
Point3D a, b, c;
Plane3D() {}
Plane3D(Point3D a, Point3D b, Point3D c): a(a), b(b), c(c) {}
void read() {
a.read(), b.read(), c.read();
}
}; struct Circle3D {
Point3D c;
double r;
Circle3D() {}
Circle3D(Point3D c, double r): c(c), r(r) {}
void read() {
c.read();
scanf("%lf", &r);
}
}; double dist(const Point3D &a, const Point3D &b) {
return (a - b).length();
}
//叉积
Point3D cross(const Point3D &u, const Point3D &v) {
Point3D ret;
ret.x = u.y * v.z - u.z * v.y;
ret.y = u.z * v.x - u.x * v.z;
ret.z = u.x * v.y - u.y * v.x;
return ret;
}
//点到直线距离
double point_to_line(const Point3D &p, const Line3D &l) {
return cross(p - l.st, l.ed - l.st).length() / dist(l.ed, l.st);
}
//求两直线间的距离
double line_to_line(const Line3D u, const Line3D v) {
Point3D n = cross(u.ed - u.st, v.ed - v.st);
return fabs((u.st - v.st) * n) / n.length();
}
//取平面法向量
Point3D vector_of_plane(const Plane3D &s) {
return cross(s.a - s.b, s.b - s.c);
}
//判断两直线是否平行
bool isParallel(const Line3D &u, const Line3D &v) {
return sgn(cross(u.ed - u.st, v.ed - v.st).length()) <= ;
}
//判断直线是否与球相交
bool isIntersect(const Line3D &l, const Circle3D &cir) {
return sgn(point_to_line(cir.c, l) - cir.r) <= ;
}
//直线与平面的交点
Point3D intersect(const Line3D &l, const Plane3D &s) {
Point3D ret = vector_of_plane(s);
double t = (ret * (s.a - l.st)) / (ret * (l.ed - l.st));
return l.st + (l.ed - l.st) * t;
}
//在原点上看,两个球的交点
int intersect(const Circle3D &u, const Circle3D &v, Point3D &p1, Point3D &p2) {
double d = dist(u.c, v.c);
if(u.c == v.c || sgn(d - u.r - v.r) > || sgn(fabs(u.r - v.r) - d) > ) return ;
double t = (sqr(d) + sqr(u.r) - sqr(v.r)) / ( * d);
Point3D mid = u.c + (v.c - u.c).unit() * t;
Point3D vec = cross(mid, v.c - u.c).unit() * sqrt(zero(sqr(u.r) - sqr(t)));
p1 = mid + vec;
p2 = mid - vec;
return + sgn(vec.length());
} const int MAXN = ; Circle3D cir[MAXN];
Point3D p[MAXN * MAXN], ansVec;
int maxAns, pcnt;
int n; int count(const Point3D &vec) {
int ret = ;
for(int i = ; i < n; ++i)
ret += (sgn(point_to_line(cir[i].c, Line3D(Point3D(, , ), vec)) - cir[i].r) <= );
return ret;
} void output(const Point3D &vec) {
bool flag = false;
for(int i = ; i < n; ++i) {
if(sgn(point_to_line(cir[i].c, Line3D(Point3D(, , ), vec)) - cir[i].r) <= ) {
if(flag) putchar(' ');
flag = true;
printf("%d", i + );
}
}
printf("\n");
} int main() {
scanf("%d", &n);
for(int i = ; i < n; ++i) cir[i].read();
for(int i = ; i < n; ++i) {
double t = / cir[i].c.length();
cir[i].c = cir[i].c * t;
cir[i].r = cir[i].r * t;
}
pcnt = ;
for(int i = ; i < n; ++i)
for(int j = i + ; j < n; ++j) pcnt += intersect(cir[i], cir[j], p[pcnt], p[pcnt + ]);
maxAns = ;
for(int i = ; i < n; ++i) {
int t = count(cir[i].c);
if(t > maxAns) {
maxAns = t;
ansVec = cir[i].c;
}
}
for(int i = ; i < pcnt; ++i) {
int t = count(p[i]);
if(t > maxAns) {
maxAns = t;
ansVec = p[i];
}
}
printf("%d\n", maxAns);
output(ansVec);
}

POJ 2177 Ghost Busters(三维几何)的更多相关文章

  1. POJ 2251 Dungeon Master --- 三维BFS(用BFS求最短路)

    POJ 2251 题目大意: 给出一三维空间的地牢,要求求出由字符'S'到字符'E'的最短路径,移动方向可以是上,下,左,右,前,后,六个方向,每移动一次就耗费一分钟,要求输出最快的走出时间.不同L层 ...

  2. hdu 5839(三维几何)

    Special Tetrahedron Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  3. POJ 2251 Dungeon Master (三维BFS)

    题目链接:http://poj.org/problem?id=2251 Dungeon Master Time Limit: 1000MS   Memory Limit: 65536K Total S ...

  4. poj 2031Building a Space Station(几何判断+Kruskal最小生成树)

    /* 最小生成树 + 几何判断 Kruskal 球心之间的距离 - 两个球的半径 < 0 则说明是覆盖的!此时的距离按照0计算 */ #include<iostream> #incl ...

  5. poj 1185 炮兵阵地(三维状态压缩dP)

    题目:http://poj.org/problem?id=1185 思路: d[i][j][k]表示第i行的状态为第k个状态,第i-1行的状态为第j个状态的时候 的炮的数量. 1表示放大炮, 地形状态 ...

  6. POJ 2252 Dungeon Master 三维水bfs

    题目: http://poj.org/problem?id=2251 #include <stdio.h> #include <string.h> #include <q ...

  7. POJ 2653 Pick-up sticks(几何)

    Pick-up sticks Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13377   Accepted: 5039 D ...

  8. POJ 3304 Segments --枚举,几何

    题意: 给n条线段,问有没有一条直线,是每条线段到这条直线上的投影有一个公共点. 解法: 有公共点说明有一条这条直线的垂线过所有线段,要找一条直线过所有线段,等价于从所有线段中任选两端点形成的直线存在 ...

  9. POJ 2318 TOYS && POJ 2398 Toy Storage(几何)

    2318 TOYS 2398 Toy Storage 题意 : 给你n块板的坐标,m个玩具的具体坐标,2318中板是有序的,而2398无序需要自己排序,2318要求输出的是每个区间内的玩具数,而231 ...

随机推荐

  1. chromium之scoped_ptr

    看看怎么使用 // Scopers help you manage ownership of a pointer, helping you easily manage the // a pointer ...

  2. ABAP术语-RFC (Remote Function Call)

    RFC (Remote Function Call) 原文:http://www.cnblogs.com/qiangsheng/archive/2008/03/12/1101581.html RFC ...

  3. 安装psutil时提示缺少python.h头文件(作记录)

    通过pip或者源码安装psutil,都会提示缺少python.h头文件,错误提示如下: ... psutil/_psutil_common.c:9:20: fatal error: Python.h: ...

  4. 【Hadoop故障处理】在高可用(HA)配置下,8088端口无法访问,resourcemanager进程无法启动问题

    [故障背景] 8088网页打不开,因8088是yarn平台的端口,所以我从yarn开始排查,首先到各个机器上使用jps命令查看yarn的各个节点是否启动,发现虽然有nodemanager进程,但是主节 ...

  5. 帝国cms发布信息时替换正文IMG图片标签里的ALT内容

    帝国cms发布信息时替换正文IMG图片标签里的ALT内容 在 e/class/userfun.php 里面增加 //替换正文IMG里的ALT内容 function user_imgalt($mid,$ ...

  6. angularjs transitions

    http://angular-transitions.mgechev.com/#/view/page1 https://scotch.io/tutorials http://stackoverflow ...

  7. linux怎么把英文版火狐浏览器改成中文

    一.按alt打开菜单栏,点击help>about firefox查看自己的火狐浏览器版本 比如我的是52.4.0版本 二打开网址 http://ftp.mozilla.org/pub/firef ...

  8. Python:TypeError: 'range' object doesn't support item deletion

    报错代码: dataIndex = range(m) del (dataIndex[randIndex]) 报错信息: 错误原因: python3 range返回的是range对象,不是数组对象 解决 ...

  9. SpringBoot入门(五)——自定义配置

    本文来自网易云社区 大部分比萨店也提供某种形式的自动配置.你可以点荤比萨.素比萨.香辣意大利比萨,或者是自动配置比萨中的极品--至尊比萨.在下单时,你并没有指定具体的辅料,你所点的比萨种类决定了所用的 ...

  10. Ruby 基础教程 1-1

    1.指定编码方式       第一种 在代码文件首行通过 #encoding:GBK的方式     第二种  ruby -E UTF-8 文件名称     第三种  irb  -E UTF-8   2 ...