POJ 1375 Intervals 解析几何 求圆的切线

题目大意:给出一个点,再给出都处于这个点之下的一些圆,求这个点光源照到这些圆上之后所得到的阴影的并集。

思路:求出每一个圆关于那个点的切线,每一个圆可以处理出来两个切线,这两个切线在x轴上交点的中间部分就是要求的阴影。最后将所有的阴影部分取并输出。

关于求切线,我是利用方向向量解方程做的。应该有更简洁的方法吧。。

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 510
#define EPS 1e-8
#define DCMP(a) (fabs(a) < EPS)
using namespace std;

struct Point{
	double x,y;

	Point(double _ = .0,double __ = .0):x(_),y(__) {}
	Point operator +(const Point &a)const {
		return Point(x + a.x,y + a.y);
	}
	Point operator -(const Point &a)const {
		return Point(x - a.x,y - a.y);
	}
	Point operator *(double a)const {
		return Point(x * a,y * a);
	}
	Point operator /(double a)const {
		return Point(x / a,y / a);
	}
	void Read() {
		scanf("%lf%lf",&x,&y);
	}
}start;
struct Circle{
	Point o;
	double r;

	void Read() {
		o.Read();
		scanf("%lf",&r);
	}
}circle;

struct Complex{
	double x,y;

	Complex(double _ = .0,double __ = .0):x(_),y(__) {}
	bool operator <(const Complex &a)const {
		if(x == a.x)	return y < a.y;
		return x < a.x;
	}
}ans[MAX];

int cnt;

inline double Calc(const Point &a,const Point &b)
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

inline Point Solve(double a1,double b1,double c1,double a2,double b2,double c2)
{
	double y = ((a1 * c2) - (a2 * c1)) / ((a1 * b2) - (a2 * b1));
	double x = (c1 - b1 * y) / a1;
	return Point(x,y);
}

inline Complex Work(const Point &p,const Circle &circle)
{
	double d = Calc(circle.o,p),_d = sqrt(d * d - circle.r * circle.r);

	Point v = Solve(circle.r,-_d,p.x - circle.o.x,_d,circle.r,p.y - circle.o.y);
	Point tangency = circle.o + v * circle.r;
	Point u = tangency - p;
	Point center = p + ((u / (p.y - tangency.y)) * p.y);
	double first = center.x;

	v = Solve(circle.r,_d,p.x - circle.o.x,-_d,circle.r,p.y - circle.o.y);
	tangency = circle.o + v * circle.r;
	u = tangency - p;
	center = p + ((u / (p.y - tangency.y)) * p.y);
	double second = center.x;

	return Complex(second,first);
}

int main()
{
	while(scanf("%d",&cnt),cnt) {
		start.Read();
		for(int i = 1; i <= cnt; ++i) {
			circle.Read();
			ans[i] = Work(start,circle);
		}
		sort(ans + 1,ans + cnt + 1);
		double l = ans[1].x,r = ans[1].y;
		for(int i = 2; i <= cnt; ++i) {
			if(ans[i].x > r) {
				printf("%.2f %.2f\n",l,r);
				l = ans[i].x,r = ans[i].y;
			}
			else	r = max(r,ans[i].y);
		}
		printf("%.2f %.2f\n\n",l,r);
	}
	return 0;
}

时间: 2024-07-31 23:02:26

POJ 1375 Intervals 解析几何 求圆的切线的相关文章

POJ 1375 Intervals | 解析几何

参考了这个博客 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; struct point { double x,y; point(){}; point(double _x,double _y) { x=_x,y=_y; } }p,q; struct range { double l,r; bool operator <

poj 1375 Intervals(解析几何 过圆外一点求与圆的切线)

题目大意:给出一个光源,给出一些圆,求投影区间. 如图,先可以求出角a,通过半径与PQ距离,而角b也可以求出.那么就可以求出两条切线与Y轴的夹角,分别为a+b,b-a. 之后利用角度求出各投影线段的左右顶点,排序判断即可. #include<iostream> #include<algorithm> #include<cmath> #include<cstdio> using namespace std; struct Point { double x,y;

POJ 1375 Intervals

解析几何,利用直角三角形asin函数求出角来,然后根据y就可以算出x了 最后把点排序一下,入点+1,出点-1,由0变为1则是入点,由1变为0时则是出点 #include<stdio.h> #include<math.h> #include<algorithm> #include<string.h> using namespace std; struct Circle{ double x,y,r; }; struct Node{ double x; int f

poj1375Intervals(点到圆的切线)

链接 貌似这样的叫解析几何 重点如何求得过光源到圆的切线与地板的交点x坐标,可以通过角度及距离来算,如图, 根据距离和半径可以求得角度a.b.r,自然也可以求得d1,d2. 至于方向问题,在求r得时候 可以使r = asin((p.x-c.x)/d) p为源点,c为圆心 ,d为两点距离. 若在反方向,自然r为负角 ,并不影响最后的结果. 排序后,统计区间就可以了. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstr

POJ 1201 Intervals(图论-差分约束)

Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20779   Accepted: 7863 Description You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a program that: reads the number of intervals, their end po

POJ 1375

可以通过顶角角度来计算切线与坐标轴的坐标 开始还以为有公式可以算,谁知道原来是解二元一次方程,靠.. #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int MAX=1050; struct point{ double x; int flag; point(){ flag=0;} }p[MAX]; do

JAVA求圆的面积

import java.text.DecimalFormat;import java.util.Scanner; public class TheAreaOfCircle { public static void main(String[] args) { /*问题描述 给定圆的半径r,求圆的面积. 输入格式 输入包含一个整数r,表示圆的半径. 输出格式 输出一行,包含一个实数,四舍五入保留小数点后7位,表示圆的面积. 说明:在本题中,输入是一个整数,但是输出是一个实数. 对于实数输出的问题,请

c++入门第一天(求圆的面积)

看了一会书,发现C++和C虽然于发上相似,但是解决问题的方式还是不一样的,毕竟面向对象和面向过程是两种不同的思维方式.下面就通过一个求圆的面积的例子,比较C和C++的不同. 需求:输入圆的半径,求解圆的面积 使用C语言来解决:1.定义两个变量半径r.面积s;  2.输入半径;  3.打印结果. 以下是源代码: #include <stdio.h> int main01() { double r, s; //定义变量圆和半径 printf("请输入圆的半径:"); scanf

POJ 2299 Ultra-QuickSort(归并排序求逆序对数)

题目地址:POJ 2299 今天下午的多校看来没有白做...实在做不出题闲着无聊看小白鼠学会了个归并排序.哈哈. 归并排序简单地说其实就是先分成一个二叉树直至单个,然后依次从最底层不断进行合并,逆序对数就是在合并的过程中,加入后面的那段中到了比他大的时候,那后面的那些就都是比他大的,都是逆序对数,所以直接加上即可.网上资料很多,就不细说了..用了分治的思想. 自己根据理解写的代码,考虑的太不全面了..又调了好长时间... 代码如下: #include <algorithm> #include