鏈接:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 3675 | Accepted: 1056 |
Description
Within this model, the x-axis has been aligned with the level of the floor. The light is considered to be a point light source with integer co-ordinates [bx,by]. The pipes are represented by circles. The center of the circle i has the integer co-ordinates [cxi,cyi] and an integer radius ri. As pipes are made from solid material, circles cannot overlap. Pipes cannot reflect the light and the light cannot go through the pipes. You have to write a program which will determine the non-overlapping intervals on the x-axis where there is, due to the pipes, no light from the light source.
Input
Output
Sample Input
6 300 450 70 50 30 120 20 20 270 40 10 250 85 20 220 30 30 380 100 100 1 300 300 300 150 90 1 300 300 390 150 90 0
Sample Output
0.72 78.86 88.50 133.94 181.04 549.93 75.00 525.00 300.00 862.50
Source
算法: 計算幾何 定點做圓的切線 向量的旋轉
題意:
思路:
//rad是弧度
//向量 A 逆時針旋轉 rad
Vector Rotate(Vector A, double rad) {
return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
已知一條直線的方向 V 和線上一定點 P , 求其與 X 軸的交點
//知道直線方向向量,方向和定點,求與 X 軸的交點,返回交點的橫座標值
double PointOfSkewToPoint(Vector V, Point P) {
double k1 = V.x / V.y; //斜率的倒數 ,方便處理了垂直於 X 軸的情況 x = ky +b;
double b1 = P.x - k1*P.y; // 與 X 軸的交點
return b1;
}
PS:關於點斜式:如果直線有垂直於 X 軸的情況就用 x = k1*y + b1
注意:
code:
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 510;
int n;
struct Point {
double x,y;
Point() {}
Point(double _x, double _y) {
x = _x; y = _y;
}
Point operator - (const Point &b) const {
return Point(x-b.x, y-b.y);
}
double operator *(const Point &b) const {
return x*b.x + y*b.y;
}
double operator ^(const Point &b) const {
return x*b.y - y*b.x;
}
}Ceil;
typedef Point Vector;
//rad是弧度
//向量 A 逆時針旋轉 rad
Vector Rotate(Vector A, double rad) {
return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
//計算向量極角
double angle(Vector V ) {
return atan2(V.y, V.x);
}
double Length(Vector V) {
return sqrt(V.x*V.x+V.y*V.y);
}
struct Circle {
Point c;
double r;
Circle() {}
Circle(Point _c, double _r) {
c = _c; r = _r;
}
Point point(double a) { // a 爲相對於 X 軸的正方向逆時針偏轉角度
return Point(c.x+cos(a)*r, c.y+sin(a)*r);
}
}circle;
struct Node{
double st,en;
}ans[maxn];
const double eps = 1e-5;
int dcmp(double x) {
if(x < eps) return 0;
else return x < 0 ? -1 : 1;
}
//知道直線方向向量,方向和定點,求與 X 軸的交點,返回交點的橫座標值
double PointOfSkewToPoint(Vector V, Point P) {
double k1 = V.x / V.y; //斜率的倒數 ,方便處理了垂直於 X 軸的情況 x = ky +b;
double b1 = P.x - k1*P.y; // 與 X 軸的交點
return b1;
}
//處理第 index 個圓, 計算其在 X 軸產生的陰影部分
void Tangents(int index) {
Circle C = circle;
Vector u = C.c - Ceil;
double distance = Length(u);
double ang = asin(C.r / distance);
Vector v1 = Rotate(u, -ang); //st
Vector v2 = Rotate(u, +ang); //en
ans[index].st = PointOfSkewToPoint(v1, Ceil);
ans[index].en = PointOfSkewToPoint(v2, Ceil);
}
bool cmp(Node a, Node b) {
return (a.st == b.st && a.en <= b.en) || a.st < b.st;
}
int main()
{
while(scanf("%d", &n) != EOF) {
if(n == 0) break;
double x,y,r;
scanf("%lf%lf", &x,&y); Ceil = Point(x, y);
for(int i = 0; i < n; i++) { //邊輸入邊處理每一個圓
scanf("%lf%lf%lf", &x, &y, &r);
circle = Circle(Point(x, y), r);
Tangents(i);
}
sort(ans, ans+n, cmp);
int index = 0;
for(int i = 1; i < n; i++) { //合併重疊的
if(ans[i].st <= ans[index].en) ans[index].en = max(ans[index].en, ans[i].en); //注意:是取二者中較大的, 而不是 ans[i].en, 貢獻一次WA
else ans[++index] = ans[i];
}
for(int i = 0; i <= index; i++)
printf("%.2lf %.2lf\n", ans[i].st, ans[i].en);
printf("\n");
}
return 0;
}