UVA 11796 Dog Distance

用到了 物理的相對運動, 其實就是向量, 兩個向量相減就是他們相對位移的方向


題意:

有甲乙兩條狗分別沿着一條折線奔跑,已知它們同時從各自的起點出發,同時到達各自的終點。求整個過程中兩條狗的最大距離Max與最小距離Min的差值。

分析:

假設甲乙的路線都是一條線段的簡單情況。運動是相對的,我們假定甲不動,乙相對甲的運動也是勻速直線運動。所以就將問題轉化成了點到直線的最小和最大距離。

甲或乙每到達一個拐點所對應的時刻稱作“關鍵點”,那麼沒兩個關鍵點之間的運動都可看做上面分析的簡單情況。我們只要及時更新甲乙的位置即可。

LenA和LenB分別是兩條路線的總長,因爲運動時間相同,不妨設二者的運動速度爲LenA和LenB,這樣總時間爲1

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

struct Point
{
	double x, y;
	Point (double x = 0, double y = 0) : x(x), y(y) { } //構造函數, 方便代碼書寫
};
typedef Point myvector;
Point a[60], b[60];
double Max, Min;

// 向量 + 向量 = 向量
myvector operator + (myvector A, myvector B) { return myvector(A.x + B.x, A.y + B.y); }
// 點 - 點 = 向量
myvector operator - (Point A, Point B) { return myvector(A.x - B.x, A.y - B.y); }
//向量 * 數 = 向量
myvector operator * (myvector A, double p) { return myvector(A.x * p, A.y * p); }
//向量/數 = 向量
myvector operator / (myvector A, double p) { return myvector(A.x / p, A.y / p); }
// 小於號
bool operator < (const Point & a, const Point & b)
{

	if (a.x == b.x) return a.y < b.y;
	return a.x < b.x;
}
//比較
const double eps = 1e-10;
int dcmp(double x)
{
	if(fabs (x) < eps) return 0;
	else return x < 0 ? -1 : 1;
}
// 恆等於號
bool operator ==  (const Point & a, const  Point  & b)
{
	return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
// 計算向量 A B 的點積, A*B = |A| * |B| * cosß
double Dot (myvector A, myvector B) { return A.x*B.x + A.y*B.y; }
// 計算向量 A 的長度
double Length (myvector A) { return sqrt (Dot(A, A)); }
// 計算向量 A,B 的夾角,是cos 有公式
double Angle (myvector A, myvector B)
{ return acos(Dot(A, B) / Length(A) / Length(B)); }

// 計算叉積,AxB = |A| * |B| * sinß, 得到的是與這兩個向量垂直的向量
double Cross(myvector A, myvector B) { return A.x * B.y - A.y * B.x; }
// 點到線段的距離, 有兩種可能, 一種點在線段上方, 這時候算垂直, 不在線段上方;
double DistanceToSegment(Point P, Point A, Point B)
{
	if( A == B) return Length(P-A); //如果線段是一個點
	myvector v1 = B - A, v2 = P - A, v3 = P - B;
	if(dcmp(Dot(v1, v2)) < 0)      return Length(v2);
	else if(dcmp(Dot(v1, v3)) > 0) return Length(v3);
	else return fabs(Cross(v1, v2)) / Length(v1);
}
void update(Point P, Point A, Point B)
{
    Min = min(Min, DistanceToSegment(P, A, B)); //點到線段的距離,是最近的
    Max = max(Max, Length(P-A));// 最長要麼
    Max = max(Max, Length(P-B));
}

int main()
{
	int T, m, n, Case = 0, i;
	cin >> T;
	while(T--)
	{
		double LenA = 0.0, LenB = 0.0;
		cin >> m >> n;
		for(i = 0; i < m; i++)
		{
			cin >> a[i].x >> a[i].y;
			if(i > 0)
				LenA += Length(a[i]-a[i-1]);//計算出來A的路程總長,設1s到達,則又是他的速度
		}

		for(i = 0; i < n; i++)
		{
			cin >> b[i].x >> b[i].y;
			if(i > 0)
				LenB += Length(b[i]-b[i-1]);
		}

		int Sa = 0, Sb = 0;        //A B當前端點的編號
        Point Pa = a[0], Pb = b[0];
        Min = 1e9, Max = -1e9;
        while(Sa < m - 1 && Sb < n - 1)
        {
            double La = Length(a[Sa+1] - Pa);    //AB分別到下一拐點的距離
            double Lb = Length(b[Sb+1] - Pb);
            double t = min(La / LenA, Lb / LenB);
            myvector Va = ((a[Sa+1] - Pa) / La) //這段時間的單位向量
            								* t * LenA; //這段時間內單位向量所走向量
            myvector Vb = ((b[Sb+1] - Pb) / Lb) * t * LenB;
            //printf("Va %f %f   Vb %f %f\n", Va.x, Va.y, Vb.x,  Vb.y);
            update(Pa, Pb, Pb + Vb - Va);
            Pa = Pa + Va;
            Pb = Pb + Vb;
            if(Pa == a[Sa+1])    Sa++;
            if(Pb == b[Sb+1])    Sb++;
        }

        printf("Case %d: %.0lf\n", ++Case, Max - Min);
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章