New Game!- 牛客

题意

有两条平行直线(L_1:Ax + By + C_1 = 0)(L_2:Ax + By + C_2 = 0),有n个圆(C_i:(x - x_i)^2 + (y - y_i)^2 = r_i^2)。人在直线上、圆上、圆内行走不消耗体力。在其它位置上由S点走到T点消耗的体力为S和T的欧几里得距离。问从(L_1)走到(L_2)需要的最少体力。((n le 1000)

题解

代码

const int N = 1005;

int n;
bool use[N];
double A, B, C1, C2;
double cost[N][N], d[N];

void DJS(int st) {
    rep(i, 0, N) use[i] = 0, d[i] = INF32 * 1.0;
    d[st] = 0;
    while(true) {
        int u = -1;
        Rep(i, 1, n + 2) if (!use[i] && (u == -1 || d[i] < d[u])) u = i;

        if (u == -1) break;
        use[u] = 1;

        Rep(i, 1, n + 2) d[i] = min(d[i], d[u] + cost[u][i]);
    }
    printf("%.6f
", d[n + 2]);
}

struct Point {
    double x, y, r;
} p[N];

double compute(double x1, double y1, double x2, double y2) {
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

int main()
{
    cin >> n >> A >> B >> C1 >> C2;
    Rep(i, 1, n) cin >> p[i].x >> p[i].y >> p[i].r;
    Rep(i, 1, n) {
        Rep(j, i + 1, n) {
            double tp = compute(p[i].x, p[i].y, p[j].x, p[j].y);
            cost[i][j] = cost[j][i] = max(0.0, tp - p[i].r - p[j].r);
        }
    }
    Rep(i, 1, n) {
        double tp = fabs(A * p[i].x + B * p[i].y + C1) / sqrt(A * A + B * B) - p[i].r;
        double sp = fabs(A * p[i].x + B * p[i].y + C2) / sqrt(A * A + B * B) - p[i].r;

        cost[n + 1][i] = cost[i][n + 1] = max(0.0, tp);
        cost[n + 2][i] = cost[i][n + 2] = max(0.0, sp);
    }
    cost[n + 1][n + 2] = cost[n + 2][n + 1] = fabs(C1 - C2) / sqrt(A * A + B * B);

    DJS(n + 1);
    return 0;
}

原文地址:https://www.cnblogs.com/zgglj-com/p/9735344.html