LOJ 3156: "NOI2019" маршрут домой

Тема Портал: LOJ # 3156 .

Описание Значение вопросов:

Существует \ (п- \) точки \ (т \) ребра ориентированного графа, есть две боковые веса \ (p_i \) и \ (q_i \) (\ (P_i <q_i \) ) указывает на то, если \ (p_i \) раз на эту сторону начальной точки, то \ (q_i \) время , чтобы дойти до конца этого края.

Вы должны планировать маршрут, так что с самого начала \ (1 \) , начиная точку вдоль этого маршрута для достижения конечной \ (п \) точки.

Предположим , что маршрут проходит сторона последовательно будет \ (\ {A_1, A_2, \ ldots, a_k \} \) , необходимо убедиться , что \ (I-Q_ {A_. 1} {} \ {a_i Le Р-} \) .
Расход этого маршрута \ (\ displaystyle q_ {a_k} + \ sum_ {я = 2} ^ {к} F (р- {a_i} -q_ {а_ {я-1}}) + F (р- {a_1 }) \) , где \ (F (X) = \ mathrm {А} + х ^ 2 \ mathrm {B} + X , \ mathrm {C} , \) .

Вы должны сделать стоимость планируемого маршрута минимальной мощности этой минимальной цены.

Решение:

Передача между стоимостью квадратичной функции, будет очевидно, наклон DP модель оптимизации.

Рассмотрим \ (\ mathrm {е} [ я] \) представлен через первый \ (I \) кромки после того, как \ (\ F СУММА ({a_j Р- А_ {} {j -. Q_ 1}}) \) , из формула Джейн:

\ [\ Начинаются {выровнен} \ mathrm {F} [I] & = \ min_ {Y_j = x_i, q_j \ ле p_i} \ {\ mathrm {F} [J] + \ mathrm {А} (p_i-q_j) ^ 2 + \ mathrm {B} (p_i-q_j) + \ mathrm {C}, \ \\} & = \ min_ {Y_j = x_i, q_j \ ле p_i} \ {\ mathrm {F} [J] + \ mathrm {А} p_i ^ 2-2 \ mathrm {А} p_iq_j + \ mathrm {А} q_j ^ 2 + \ mathrm {B} p_i- \ mathrm {B} q_j + \ mathrm {C}, \ \\} & = \ min_ { Y_j = x_i, q_j \ ле p_i} \ {\ mathrm {F} [J] + \ mathrm {А} q_j ^ 2- \ mathrm {B} q_j-2 \ mathrm {А} p_iq_j \} + \ mathrm {A } p_i ^ 2 + \ mathrm {B} p_i + \ mathrm {C}, \ {конец выровнен} \]

Выражение , где наклон очевидно, \ (Х \) координаты \ (q_i \) , \ (Y \) координаты \ (\ mathrm {F} [ I] + \ mathrm {А} q_i ^ 2- \ mathrm {B} q_i \) , так что \ (\ mathrm {D} _i = \ mathrm {А} P_i ^ 2 + \ mathrm {B} P_i + \ mathrm {C} , \) ,
то \ (\ displaystyle \ mathrm {е } [I] = \ mathrm - i} + {D \ {Y_j = min_ x_i, Q_j \ Ле P_i} \ {2-Y_j \ mathrm p_ix_j {А} \} \) .

Исследование двух правовых точка перехода \ (J \) и \ (К \) (\ (x_j <x_k \) ), точка перехода \ (J \) , чем точка перехода \ (К \) , предпочтительно , если и только если:

\ [\ {Начинаются выровнены} Y_j-2 \ mathrm {А} p_ix_j & <y_k-2 \ mathrm {А} p_ix_k \\ 2 \ mathrm {A} p_i (x_k-x_j) & <y_k-Y_j \\\ гидроразрыва { y_k-Y_j} {x_k-x_j} &> 2 \ mathrm {А} p_i \ {конец выровнен} \]

Поскольку число больше, чем диапазон чисел, так что сохранение выпуклой оболочки.

Обратите внимание , что для удобства, в соответствии с порядком обновления \ (P_i \) от мала до велика, так что правый наклон увеличивается, но не обновили сразу добавляемые выпуклую оболочку, но не должны ждать , пока очередь соответствующего \ (P_i \) , когда затем добавить.

Ниже приведен код, время сложность \ (\ mathcal {O} (п-т + \ Q макс) \) :

#include <cstdio>
#include <algorithm>
#include <vector>

typedef double db;
const int MN = 100005, MM = 200005, MQ = 1005;

int N, M, _A, _B, _C, Ans = 0x3f3f3f3f;
int d[MN], eu[MM], ev[MM], ep[MM], eq[MM];
std::vector<int> vp[MQ], vq[MQ];
int X[MM], Y[MM], f[MM];
int _stk[MM], *stk[MN], _l[MN], _r[MN];

inline db Slope(int i, int j) {
    if (X[i] == X[j]) return Y[i] == Y[j] ? 0 : Y[i] < Y[j] ? 1e99 : -1e99;
    return (db)(Y[j] - Y[i]) / (X[j] - X[i]);
}

int main() {
    freopen("route.in", "r", stdin);
    freopen("route.out", "w", stdout);
    scanf("%d%d%d%d%d", &N, &M, &_A, &_B, &_C);
    ev[0] = 1, vq[0].push_back(0), ++d[1];
    for (int i = 1; i <= M; ++i) {
        scanf("%d%d%d%d", &eu[i], &ev[i], &ep[i], &eq[i]);
        vp[ep[i]].push_back(i);
        vq[eq[i]].push_back(i);
        ++d[ev[i]];
    }
    stk[0] = _stk;
    for (int i = 1; i <= N; ++i) stk[i] = stk[i - 1] + d[i - 1], _l[i] = 1;
    for (int t = 0; t <= 1000; ++t) {
        for (auto i : vq[t]) {
            int u = ev[i], *st = stk[u], l = _l[u], &r = _r[u];
            while (l < r && Slope(st[r - 1], st[r]) > Slope(st[r], i)) --r;
            st[++r] = i;
            if (u == N && Ans > f[i] + eq[i]) Ans = f[i] + eq[i];
        }
        for (auto i : vp[t]) {
            int u = eu[i], *st = stk[u], &l = _l[u], r = _r[u];
            while (l < r && Slope(st[l], st[l + 1]) < 2 * _A * t) ++l;
            if (l <= r) f[i] = Y[st[l]] - 2 * _A * t * X[st[l]] + _A * t * t + _B * t + _C;
            else f[i] = 0x3f3f3f3f;
            X[i] = eq[i], Y[i] = f[i] + _A * eq[i] * eq[i] - _B * eq[i];
        }
    }
    printf("%d\n", Ans);
    return 0;
}

рекомендация

отwww.cnblogs.com/PinkRabbit/p/NOI2019D1T1.html
рекомендация