2013-09-16 08:55:27Morris

[UVA][三分二分] 11574 - Colliding Traffic

Problem C: Colliding Traffic

For a boat on a small, constrained body of water, other traffic can be a major hazard. The more traffic there is in the same area, the higher the risk of a collision.

Your job is to monitor traffic and help detect likely collisions before they occur. You have sensors to detect the position, direction, and speed of each boat. Assuming the direction and speed remain constant, your task is to determine whether any of the boats will collide. Two boats are considered to collide if they come within a given distance of each other.

Input Specification

The first line of input contains a single integer c, the number of test cases to follow. Each test case starts with a line containing two numbers, n, the number of boats, and r, the collision distance. Two boats are considered to collide if they come within r metres of each other. There will be no more than 1000 boats. Each boat is identified by a line containing four numbers x, y, d, s. The numbers x and y give the current position of the boat as a distance east and north, respectively, from a common origin, and will be between -1000 and 1000, inclusive. The lake is small enough that we can model it as a flat surface. The number d gives the direction in which the boat is heading in degrees clockwise from north (so east is 90 degrees). The number s gives the speed of the boat in metres per second, and will be between 0.001 and 1000. Note that r, x, y, d, and s are not necessarily integers. The input data will be such that the answer will not change if any of the numbers x, y, d and s are changed by 10^-6 or less. If any two boats are within r metres of each other in their initial position, they are already collided, so you should output 0 for that case.

Sample Input

2
2 5
0 0 90 1
10 10 180 1
2 10
0 0 0 0
8 8 270 1

Output Specification

For each test case, output a line containing a single integer, the number of seconds, rounded to the nearest second, before any of the boats come within r metres of each other. If none of the boats ever collide, output the line:
No collision.

Output for Sample Input

6
2

Ondřej Lhoták, Richard Peng


題目描述:


給定每艘船的位置以及前向方向和速度,問第一次碰撞的時間,碰撞是看兩點是否在有效範圍內。

題目解法:

窮舉任兩艘可能的碰撞時間取最小即可。
如何決定兩艘船的碰撞時間?
兩條線(船行徑路線)可不必交於一點也可能產生碰撞,平行或重疊也會有追趕的可能。
只考慮兩船的最近距離,則發現必然是呈現凸性(遠-近-遠)或者(遠-無窮遠)。
可利用三分找到最近點的時間,但碰撞可能發生在最近點之前。
再考慮一下,現在已經可以斷出(遠-近) 接著再進行二分找有效範圍的碰撞。
結論:窮舉(三分+二分)


#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
struct ship {
    double x, y, d, s;
    double sin, cos;
};
ship S[1005];
int n;
double r;
const double pi = acos(-1);
#define eps 1e-8
double distAB(ship &a, ship &b, double time) {
    static double ax, ay, bx, by;
    ax = a.x + a.s*a.sin*time;
    ay = a.y + a.s*a.cos*time;
    bx = b.x + b.s*b.sin*time;
    by = b.y + b.s*b.cos*time;
    return (ax-bx)*(ax-bx)+(ay-by)*(ay-by);
}
double calcCollide(ship a, ship b, double R) {
    if(distAB(a, b, 0) <= R*R)
        return 0;
    double l, r, mid, midmid;//ternary search
    double md = 1e+30, mmd;
    l = 0, r = 1000;
    while(fabs(l-r) > 1e-2) {
        mid = (l+r)/2;
        midmid = (mid+r)/2;
        md = distAB(a, b, mid);
        mmd = distAB(a, b, midmid);
        if(md <= mmd)    r = midmid;
        else              l = mid;
    }
    if(md > R*R)    return 1e+30;
    // binary search
    r = l, l = 0;
    while(fabs(l-r) > 1e-2) {
        mid = (l+r)/2;
        md = distAB(a, b, mid);
        if(md > R*R)
            l = mid;
        else
            r = mid;
    }
    return l;
}
int main() {
    int testcase;
    int i, j, k;
    scanf("%d", &testcase);
    while(testcase--) {
        scanf("%d %lf", &n, &r);
        for(i = 0; i < n; i++) {
            scanf("%lf %lf %lf %lf", &S[i].x, &S[i].y, &S[i].d, &S[i].s);
            S[i].sin = sin(S[i].d/180.0*pi);
            S[i].cos = cos(S[i].d/180.0*pi);
        }
        double ret = 1e+30;
        for(i = 0; i < n; i++) {
            for(j = i+1; j < n; j++) {
                double time = calcCollide(S[i], S[j], r);
                ret = min(ret, time);
            }
        }
        if(ret > 1e+10)
            puts("No collision.");
        else
            printf("%.lf\n", ret);
    }
    return 0;
}