雪色光晕(计算几何+暴力)

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了雪色光晕(计算几何+暴力)相关的知识,希望对你有一定的参考价值。

题目链接

https://ac.nowcoder.com/acm/contest/23479/D

题面

思路

每一秒都有一个方向向量,然后每一秒都往这个方向移动一次,那么小红和小果之间的距离就只有三种情况

  • 第一种就是当前位置(没移动)到小果的距离
  • 第二种就是终点位置(移动后)到小果的距离
  • 第三种就是小果到这个移动线段(起点到终点)的距离
    那么我们直接分三种情况去一个min就好了
    关于点到线的距离博客讲解:https://blog.csdn.net/angelazy/article/details/38489293

附上出题人的讲解(非常详细)


本题要求一个固定的点到一条折线的最短距离。由于折线可以看成是很多条线段,所以可以规约成点到线段的最短距离。

(虽然这个是板子,但不建议直接去百度,毕竟赛场上没有百度)

显然,最终的答案一定为以下两种情况的一种:点到直线的最短距离、或点到线段某个端点的最短距离。

什么时候会遇到第二种情况呢?当且仅当点到直线的最短距离所对应的那个点不在线段上。

所以这道题一个最笨的方法就是:先根据线段求出直线两点式,然后求斜率乘积为-1(这样才能垂直)的直线,求出点斜式(还要特判斜率不存在的情况),这样求出两个直线交点,判断交点在不在线段上。如果在的话直接输出初始点到交点距离,否则输出初始点到线段两个端点的最小那个距离。

如果这道题用这种方法来做,计算量将非常大,题目难度也直接飙上1700+。事实上,本题有更简单的做法:

首先如何判断最终能不能取到点到直线距离呢?很简单,把点 PP 和线段两个端点 AA 和 BB ,这三个点连接成一个三角形,判断该三角形的角 AA 和角 BB 是否是钝角即可。判断钝角可以直接用勾股定理: a 2 + b 2 < c 2 a^2+b^2<c^2 a2+b2<c2则角 C 为钝角。

然后如何求点到直线的距离呢?也很简单,P到直线ABAB 的距离即三角形 PABPAB 中ABAB边上的高。直接用 2 ∗ S A B C / A B 2*S_ABC/AB 2SABC/AB

/AB即可。而三角形面积可以直接用海伦公式: S = p ∗ ( p − a ) ∗ ( p − b ) ∗ ( p − c ) S=\\sqrtp*(p-a)*(p-b)*(p-c) S=p(pa)(pb)(pc)
可以发现,换一个做法,原本计算量巨大的题目将极大的减少做题的负担。在赛场上如果发现某题计算量非常大,不妨洗个脸冷静一下,换一个思路可能会豁然开朗。

*请注意,本题如果直接用网上的long long 存点的板子,可能会导致答案错误。因为在计算过程中会出现超过10^9的情况,这样在计算勾股定理的时候再一个平方就会出现爆long long精度的问题。解决办法要么使用__int128或者高精度,要么直接用double存点。 *

代码

my

#include<bits/stdc++.h>
using namespace std;
//----------------自定义部分----------------
#define ll long long
#define mod 1000000007
#define endl "\\n"
#define PII pair<int,int>
#define INF 0x3f3f3f3f

int dx[4] = -1, 0, 1, 0, dy[4] = 0, 1, 0, -1;

ll ksm(ll a,ll b) 
	ll ans = 1;
	for(;b;b>>=1LL) 
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
	
	return ans;


ll lowbit(ll x)return -x & x;

const int N = 2e6+10;
//----------------自定义部分----------------
int n;
struct point  double x, y; ;
point p1,p2,p3;

double get_distance(point p, point A, point B) 
	point Ap, Ab, Bp;
	Ap.x = p.x - A.x, Ap.y = p.y - A.y;
	Ab.x = B.x - A.x, Ab.y = B.y - A.y;
	Bp.x = p.x - B.x, Bp.y = p.y - B.y;
	double r = (Ap.x*Ab.x + Ap.y*Ab.y)*1.0 / (Ab.x*Ab.x + Ab.y*Ab.y);
	
	if (r <= 0)return sqrt(Ap.x*Ap.x*1.0 + Ap.y*Ap.y);
	if (r >= 1)return sqrt(Bp.x*Bp.x*1.0+Bp.y*Bp.y);
	double px = A.x + Ab.x*r;
	double py = A.y + Ab.y*r;
	return sqrt((p.x-px)*(p.x-px)+(p.y-py)*(p.y-py));


double f(point a,point b)
	return sqrt(pow(a.x-b.x,2.0) + pow(a.y-b.y,2.0));


int main()

	scanf("%d",&n);
	scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
	double ans = f(p1,p2);
	while(n--)
		scanf("%lf%lf",&p3.x,&p3.y);
		point p4 = p1.x + p3.x,p1.y+p3.y;
		ans = min(ans,f(p1,p2));
		ans = min(ans,get_distance(p2,p1,p4));
		p1 = p4;
	
	printf("%.9lf\\n",ans);
	
	return 0;

标程

#include<bits/stdc++.h>
using namespace std;
struct point
    double x,y;
    point(double x,double y):x(x),y(y)
;
double dis(point a,point b)
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

double ar(point A,point B,point C) //三点三角形面积
    double a=dis(B,C),b=dis(A,C),c=dis(A,B);
    double p=(a+b+c)/2;
    return sqrt(p*(p-a)*(p-b)*(p-c));

int jud(point A,point B,point C)       //判断角ABC是钝角
    double a=dis(B,C),b=dis(A,C),c=dis(A,B);

    return b*b>a*a+c*c;

double f(point a,point b,point c)  //c点到ab线段的最小距离
    double d1=dis(a,c),d2=dis(b,c);
    if(jud(c,a,b)||jud(c,b,a))
        return min(d1,d2);
    double s=ar(a,b,c);
    double d3=2*s/dis(a,b);
    return min(min(d1,d2),d3);

int main()
    int n,i,j,k;
    double x,y,x0,y0;
    cin>>n;
    cin>>x0>>y0>>x>>y;
    point purple(x,y);
    point red(x0,y0);
    double res=1e16;
    for(i=0;i<n;i++)
        double xt,yt;
        cin>>xt>>yt;
        point temp(red.x+xt,red.y+yt);
        res=min(res,f(red,temp,purple));
        red=temp;
    
    printf("%.8f",res);

以上是关于雪色光晕(计算几何+暴力)的主要内容,如果未能解决你的问题,请参考以下文章

2022牛客寒假算法基础集训营 4 全部题解

2022牛客寒假算法基础集训营4 ABCDEFGHIJKL

LibreOJ #517. 「LibreOJ β Round #2」计算几何瞎暴力

HDOJ 5839 计算几何+暴力

“玲珑杯”ACM比赛 Round #18 A 计算几何你瞎暴力(瞎暴力)

HDU 6697 Closest Pair of Segments (计算几何 暴力)