HDU 5572 An Easy Physics Problem 【直线与圆的关系】


传送门:HDU 5572


An Easy Physics Problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Problem Description
On an infinite smooth table, there’s a big round fixed cylinder and a little ball whose volume can be ignored.
Currently the ball stands still at point A, then we’ll give it an initial speed and a direction. If the ball hits the cylinder, it will bounce back with no energy losses.
We’re just curious about whether the ball will pass point B after some time.

Input
First line contains an integer T, which indicates the number of test cases.
Every test case contains three lines.
The first line contains three integers Ox, Oy and r, indicating the center of cylinder is (Ox,Oy) and its radius is r.
The second line contains four integers Ax, Ay, Vx and Vy, indicating the coordinate of A is (Ax,Ay) and the initial direction vector is (Vx,Vy).
The last line contains two integers Bx and By, indicating the coordinate of point B is (Bx,By).
⋅ 1 ≤ T ≤ 100.
⋅ |Ox|,|Oy|≤ 1000.
⋅ 1 ≤ r ≤ 100.
⋅ |Ax|,|Ay|,|Bx|,|By|≤ 1000.
⋅ |Vx|,|Vy|≤ 1000.
⋅ Vx≠0 or Vy≠0.
⋅ both A and B are outside of the cylinder and they are not at same position.

Output
For every test case, you should output “Case #x: y”, where x indicates the case number and counts from 1. y is “Yes” if the ball will pass point B after some time, otherwise y is “No”.

Sample Input
2
0 0 1
2 2 0 1
-1 -1
0 0 1
-1 2 1 -1
1 2

Sample Output
Case #1: No
Case #2: Yes



题解:
先判断射线和圆交点个数,如果小于2再看是否B在A的前进方向上,没有则NO,否则YES。如果等于2,就先找到第一个交点,将这个交点和圆心连成直线,那么A的路径关于这条直线对称,那么如果A关于此直线的对称点在圆心->B路径上,则可以相撞,否则不行。

(重复写了好几遍代码,WA到崩溃,果然计算集合的题目模板要好)


AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const double eps=1e-8;
int sgn(double x)//判断一个数>,<,=0
{
	if(fabs(x)<eps) return 0;
	if(x<0) return -1;
	else return 1;
}
int dcmp(double x, double y)
{
	if(fabs(x - y) < eps)
		return 0;
	if(x > y)
		return 1;
	return -1;
}
struct point //点的操作
{
	double x,y;
	point() {
	}
	point(double x,double y) : x(x),y(y) {
	}
	void input()
	{
		scanf("%lf%lf",&x,&y);
	}
	bool operator ==(point b)const {
		return sgn(x-b.x)==0&&sgn(y-b.y)==0;
	}
	bool operator <(point b)const {
		return sgn(x-b.x)==0 ? sgn(y-b.y)<0 : x<b.x;
	}
	point operator -(const point &b)const {
		return point(x-b.x,y-b.y);
	}
	point operator +(const point &b)const {
		return point(x+b.x,y+b.y);
	}
	point operator *(const double &k)const {
		return point(x*k,y*k);
	}
	point operator /(const double &k)const {
		return point(x/k,y/k);
	}
	double operator ^(const point &b)const { //叉乘
		return x*b.y-y*b.x;
	}
	double operator *(const point &b)const { //点乘
		return x*b.x+y*b.y;
	}
	double len(){ //返回长度
		return hypot(x,y);
	}
	double len2(){ //返回长度平方
		return x*x+y*y;
	}
	//求单位向量
	point trunc(double r){
		double l=len();
		if(!sgn(l)) return *this;
		r/=l;
		return point(x*r,y*r);
	}
};
struct line //线的操作
{
	point s,e;
	line(){

	}
	line(point _s,point _e){
		s=_s;
		e=_e;
	}
	bool operator ==(line v){
		return (s == v.s) && (e == v.e);
	}
	//返回点p在直线上的投影
	point lineprog(point p){
		return s+(((e-s)*((e-s)*(p-s)))/((e-s).len2()));
	}
	//求点p关于该直线的对称点
	point symmetrypoint(point p){
		point q=lineprog(p);
		return point(2*q.x-p.x,2*q.y-p.y);
	}
	//点是否在线段上
	bool pointonseg(point p){
		return sgn((p-s)^(e-s))==0&&sgn((p-s)*(p-e))<=0;
	}
};
struct circle//圆的操作
{
	double r;//半径
	point p;//圆心
	void input(){
		p.input();
		scanf("%lf",&r);
	}
	circle(){
	}
	circle(point _p,double _r){
		p=_p;
		r=_r;
	}
	circle(double x,double y,double _r){
		p=point(x,y);
		r=_r;
	}
	//求直线和圆的交点,返回交点个数
	int pointcrossline(line l,point &r1,point &r2){
		double dx=l.e.x-l.s.x,dy=l.e.y-l.s.y;
		double A=dx*dx+dy*dy;
		double B=2*dx*(l.s.x-p.x)+2*dy*(l.s.y-p.y);
		double C=(l.s.x-p.x)*(l.s.x-p.x)+(l.s.y-p.y)*(l.s.y-p.y)-r*r;
		double del=B*B-4*A*C;
		if(sgn(del)<0) return 0; //无解
		int cnt=0;
		double t1=(-B-sqrt(del))/(2*A);
		double t2=(-B+sqrt(del))/(2*A);
		if(sgn(t1)>=0)
		{
			r1=point(l.s.x+t1*dx,l.s.y+t1*dy);
			cnt++;
		}
		if(sgn(t2)>=0)
		{
			r2=point(l.s.x+t2*dx,l.s.y+t2*dy);
			cnt++;
		}
		return cnt;
	}
};
point A,V,B;
circle tc;
point r1,r2;
int t;
int main()
{
	int ca=0;
	scanf("%d",&t);
	while(t--)
	{
		tc.input();//输入圆心和半径
		A.input();//输入A点
		V.input();//输入方向向量V
		B.input();//输入目标点B
		int flag=0;
		int num=tc.pointcrossline(line(A,A+V),r1,r2);//r1,r2为两个交点
		if(num<2)//相切或者相离
		{
			//判断B是否在A的射线上
			point t=B-A;
			if(t.trunc(1)==V.trunc(1))
				flag=1;
			else
				flag=0;
		}
		else
		{
			line l=line(tc.p,r1);//圆心和交点的直线
			line l1=line(A,r1);//A点和交点的直线
			line l2=line(r1,B);//交点和B的直线
			point tmp=l.symmetrypoint(A);//A点关于l的对称点
			if(l1.pointonseg(B))
				flag=1;
			else if(l2.pointonseg(tmp))
				flag=1;
			else
				flag=0;
		}
		if(flag)
			printf("Case #%d: Yes\n",++ca);
		else
			printf("Case #%d: No\n",++ca);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值