hdu 5572 桌球碰撞问题

传送门


点关于直线对称公式:

点( x , y )关于直线Ax + by + C = 0 的对称点( X , Y ):


设参数方程


联立圆方程得到关于t的一元二次方程


可见c>0恒成立

分两种情况讨论:

1.小球不反弹

2(1).小球在反弹前已经经过B点

(2).小球反弹后经过b点


对于1,直接检验B是否在射线上(t > 0)

对于2:

要使方程有两个正根,则-b/2a>0,即b<0

其中有效根为较小的t

进而求出反弹点P及切线方程Ax+By+C=0

求出B关于切线对称点C,

检验C是否在射线A上


///                 .-~~~~~~~~~-._       _.-~~~~~~~~~-.
///             __.'              ~.   .~              `.__
///           .'//                  \./                  \\`.
///        .'//                     |                     \\`.
///       .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
///     .'//.-"                 `-.  |  .-'                 "-.\\`.
///   .'//______.============-..   \ | /   ..-============.______\\`.
/// .'______________________________\|/______________________________`.
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <stdio.h>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <functional>
#include <stdlib.h>
#include <time.h>
#include <bitset>
using namespace std;

#define pi acos(-1)
#define s_1(x) scanf("%d",&x)
#define s_2(x,y) scanf("%d%d",&x,&y)
#define s_3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define s_4(x,y,z,X) scanf("%d%d%d%d",&x,&y,&z,&X)
#define S_1(x) scan_d(x)
#define S_2(x,y) scan_d(x),scan_d(y)
#define S_3(x,y,z) scan_d(x),scan_d(y),scan_d(z)
#define PI acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define fOR(n,x,i) for(int i=n;i>=x;i--)
#define fOr(n,x,i) for(int i=n;i>x;i--)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");
#define db double
#define ll long long
#define mp make_pair
#define pb push_back
typedef long long LL;
typedef pair <int, int> ii;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,1,-1,-1,1};
const int dy[]={0,1,0,-1,-1,1,-1,1};
const int maxn=1e5+10;
const int maxx=4e5+10;
const double EPS=1e-8;
const double eps=1e-8;
const int mod=1e9+7;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
template <class T>
inline bool scan_d(T &ret){char c;int sgn;if (c = getchar(), c == EOF){return 0;}
while (c != '-' && (c < '0' || c > '9')){c = getchar();}sgn = (c == '-') ? -1 : 1;ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9'){ret = ret * 10 + (c - '0');}ret *= sgn;return 1;}

inline bool scan_lf(double &num){char in;double Dec=0.1;bool IsN=false,IsD=false;in=getchar();if(in==EOF) return false;
while(in!='-'&&in!='.'&&(in<'0'||in>'9'))in=getchar();if(in=='-'){IsN=true;num=0;}else if(in=='.'){IsD=true;num=0;}
else num=in-'0';if(!IsD){while(in=getchar(),in>='0'&&in<='9'){num*=10;num+=in-'0';}}
if(in!='.'){if(IsN) num=-num;return true;}else{while(in=getchar(),in>='0'&&in<='9'){num+=Dec*(in-'0');Dec*=0.1;}}
if(IsN) num=-num;return true;}

void Out(LL a){if(a < 0) { putchar('-'); a = -a; }if(a >= 10) Out(a / 10);putchar(a % 10 + '0');}
void print(LL a){ Out(a),puts("");}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
//cerr << "run time is " << clock() << endl;


int dcmp(double x)
{
    if(fabs(x) < EPS) return 0;
    else return x < 0 ? -1 : 1;
}


struct Point
{
    double x, y;
    int id;
    //Point(const Point& rhs): x(rhs.x), y(rhs.y) { } //¿½±´¹¹Ô캯Êý
    Point(double x = 0, double y = 0) : x(x), y(y) { }
    inline void input()
    {
        scanf("%lf%lf",&x,&y);
    }
    inline void print()
    {
        printf("%.6lf %.6lf\n",x,y);
    }
    bool operator == (const Point& e) const
    {
        return dcmp(x - e.x) == 0 && dcmp(y - e.y) == 0;
    }
    Point operator + (Point q){ return Point(x+q.x,y+q.y);}
    Point operator - (Point q){ return Point(x-q.x,y-q.y);}
    Point operator * (double q){ return Point(x*q,y*q);}
    Point operator / (double q){ return Point(x/q,y/q);}
    Point &operator +=(Point q){ x+=q.x;y+=q.y; return *this;}
    Point &operator -=(Point q){ x-=q.x;y-=q.y; return *this;}
    double operator *(const Point& q) const{
        return x*q.x+y*q.y;
    }
    double operator ^(const Point& q) const{
        return x*q.y-y*q.x;
    }
    double len2()
    {
        return x*x+y*y;
    }
    double len()
    {
        return sqrt(x*x+y*y);
    }
    Point change_len (double r)
    {//转化为长度为r的向量
        double l = len ();
        if (dcmp (l) == 0) return *this;//零向量返回自身
        r /= l;
        return Point (x*r, y*r);
    }
    void read()
    {
        int xx,yy;
        scanf("%d%d",&xx,&yy);
        x=xx,y=yy;
    }
    inline void prin()
    {
        printf("%.6lf %.6lf\n",x,y);
    }


};

//向量叉积  |a||b|sin<a,b>
//叉积的结果也是一个向量,是垂直于向量a,b所形成的平面,如果看成三维坐标的话是在 z 轴上,上面结果是它的模。
double Cross(Point A,Point B) { return A.x*B.y - A.y*B.x; }

//向量点积
double Dot(Point A,Point B) { return A.x*B.x + A.y*B.y; }

//向量长度
double Length(Point A) { return sqrt(Dot(A, A)); }

long double dis (Point a, Point b)
{//两个点的距离
    Point p = b-a; return p.len ();
}

//************直线 线段
struct Line
{
    Point s, e;//直线的两个点
    double k;//极角
    Line () {}
    Line (Point _s, Point _e)
    {
        s = _s, e = _e;
        k = atan2 (e.y - s.y,e.x - s.x);
    }
    double length ()
    {//求线段长度
        return dis (s, e);
    }
};

//点和直线的关系
int relation (Point p, Line l)
{
    //1:在左侧 2:在右侧 3:在直线上
    int c = dcmp (Cross (p-l.s, l.e-l.s));
    if (c < 0) return 1;
    else if (c > 0) return 2;
    else return 3;
}
//判断点在线段上
bool point_on_seg (Point p, Line l)
{
    return dcmp (Cross (p-l.s, l.e-l.s)) == 0 &&
    dcmp (Dot (p-l.s, p-l.e) <= 0);
    //如果忽略端点交点改成小于号就好了
}
//判断点在射线上
bool point_on_halfline (Point p, Line l)
{
    int id = relation (p, l);
    if (id != 3) return 0;
    return dcmp (Dot (p-l.s, l.e-l.s)) >= 0;
}

//点到直线的距离
double point_to_line (Point p, Line a)
{
    return fabs (Cross (p-a.s, a.e-a.s) / a.length ());
}
//点在直线上的投影
Point projection (Point p, Line a)
{
    return a.s + (((a.e-a.s) * Dot (a.e-a.s, p-a.s)) / (a.e-a.s).len2() );
}
//点关于直线的对称点
Point symmetry (Point p, Line a)
{
    Point q = projection (p, a);
    return Point (2*q.x-p.x, 2*q.y-p.y);
}

struct Circle
{
    Point c;
    double r;
    Circle() {}
    Circle(const Circle& rhs): c(rhs.c), r(rhs.r) { }
    Circle(const Point& c, const double& r): c(c), r(r) { }

    inline void input()
    {
        scanf("%lf%lf%lf",&c.x,&c.y,&r);
    }
    inline void print()
    {
        printf("%.6lf %.6lf\n",c.x,c.y);
    }
    Point point(double ang) const { return Point(c.x + cos(ang)*r, c.y + sin(ang)*r); } //圆心角所对应的点
    double area(void) const { return PI * r * r; }
};

//直线和圆的关系
int relation (Line a, Circle b)
{
    //0:相离 1:相切 2:相交
    double p = point_to_line (b.c, a);
    if (dcmp (p-b.r) == 0) return 1;
    return (dcmp (p-b.r) < 0 ? 2 : 0);
}
//直线和圆的交点
int line_circle_intersection (Line v, Circle u, Point &p1, Point &p2)
{
    //返回交点个数 交点保存在引用中
    if (!relation (v, u)) return 0;
    Point a = projection (u.c, v);
    double d = point_to_line (u.c, v);
    d = sqrt (u.r*u.r - d*d);
    if (dcmp (d) == 0)
    {
        p1 = a, p2 = a;
        return 1;
    }
    p1 = a + (v.e-v.s).change_len (d);
    p2 = a - (v.e-v.s).change_len (d);
    return 2;
}

Point a,b,c;
Circle q;
void solve()
{
    q.input();
    a.input();
    c.input();
    b.input();
    Point temp=Point(a.x+c.x,a.y+c.y);
    Point p1,p2;
    int num=line_circle_intersection(Line(a,temp),q,p1,p2);
    if(num<2)
    {
        if(point_on_halfline(b,Line(a,temp))) puts("Yes");
        else puts("No");
    }
    else
    {
        if(dis(a,p1)>dis(a,p2)) swap(p1,p2);
        if(point_on_seg(b,Line(a,p1)))
        {
            puts("Yes");
            return ;
        }
        Point a1=symmetry(a,Line(p1,q.c));
        if(point_on_halfline(b,Line(p1,a1))) puts("Yes");
        else puts("No");
    }
}
int main()
{
    //freopen( "in.txt" , "r" , stdin );
    //freopen( "data.txt" , "w" , stdout );
    int t=1;
    //init();
    s_1(t);
    for(int cas=1;cas<=t;cas++)
    {
        printf("Case #%d: ",cas);
        solve();
    }
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值