zoj 1309 || poj 1375 Intervals

211 篇文章 0 订阅
134 篇文章 1 订阅

求圆外一点和这些圆的投影。

直接求点和圆的切线与地面的交点,然后按x坐标从小到大排序。然后验证这些点和P的连线是否穿过某个圆,如果穿过,必然不合题意。

中间卡了下精度,如果判断是否穿过某个圆的时候不用eps,我样例都过不去 = =。。。

当然,求和地面的交点可以用解析几何的知识。。。我懒得推。。

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")
#define STOP system("pause")

using namespace std;

const int MAX = 510;
struct point {
	double x,y;
	void get()
	{
		scanf("%lf%lf",&x,&y);
	}
};
struct circle{point c;double r;};
point p;
circle c[MAX];
point ins[MAX*2];
point l1,l2;
const double eps = 1e-6;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
double disp2p(point a,point b) //  a b 两点之间的距离 
{
	return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );
}
// 叉积 (三点)
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
point Rotate(double ang, point a, point b)
{    
	b.x -= a.x; b.y -= a.y;
    point c;
    c.x = b.x * cos(ang) - b.y * sin(ang) + a.x;
    c.y = b.x * sin(ang) + b.y * cos(ang) + a.y;
    return c;
}
point l2l_inst_p(point u1,point u2,point v1,point v2)
{
	point ans = u1;
	double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/
				((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));
	ans.x += (u2.x - u1.x)*t;
	ans.y += (u2.y - u1.y)*t;
	return ans;
}

void get_point(point p,point c,double r,point &a,point &b)
{
	double l = disp2p(c,p);
	double ang = asin(r/l);
	a = Rotate(ang, p, c);
	b = Rotate(-ang, p, c);
	a = l2l_inst_p(l1, l2, p, a);
	b = l2l_inst_p(l1, l2, p, b);
}
bool cmp(point a,point b)
{
	return a.x < b.x;
}
double disp2l(point a,point l1,point l2)
{
	return fabs( crossProduct(a,l1,l2) )/disp2p(l1,l2);
}
bool solve(point ins, int n)
{
	for(int k=0; k<n; k++)
	{
		double len = disp2l(c[k].c, p, ins);
		if( xy(len,c[k].r) )
			return false;
	}
	return true;
}

int main()
{
	int n;
	
	l1.x = l1.y = 0;
	l2.x = 10; l2.y = 0;

	while( ~scanf("%d", &n) && n )
	{
		p.get();
		int cnt = 0;
		for(int i=0; i<n; i++)
		{
			c[i].c.get();
			scanf("%lf", &c[i].r);
			get_point(p, c[i].c, c[i].r, ins[cnt], ins[cnt+1]);
			cnt += 2;
		}
		
		sort(ins, ins+cnt, cmp);

		int k = 0;
		for(int i=0; i<cnt; i++)
		{
			if( solve(ins[i], n) )
			{
				k++;
				printf("%.2lf", ins[i].x);
				if( k % 2 == 0 )
					printf("\n");
				else
					printf(" ");
			}
		}
		printf("\n");
	}

return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值