POJ - 3268: Вечеринка Серебряной Коровы

Название Описание:

ввод, вывод:

 Идеи:

Прочитав вопрос, чувствую, что этот вопрос просто раз плюнуть, не правда ли, два дейкстра, лишь бы рука была, (оказывается, что я - пустышка...)

Но когда я прочитал вопрос, я увидел, что f(i), описанный в вопросе, представляет собой кратчайший путь от x до i + кратчайший путь от i до x, и, наконец, требуется max f(i).

Я был ошеломлен. Разве кратчайший путь и максимальное значение не противоречат друг другу? Разве это не смущает человека, написавшего этот вопрос (***)

Но, выслушав объяснение учителя, я постепенно немного понял. Здесь я приведу пример из класса того времени, чтобы объяснить его всем.

Циндао->Шанхай: Циндао-Цзинань-Шанхай (вперед, 6 часов); Шанхай-Циндао (обратно, 3 часа) всего 9 часов Циндао->Яньтай: Циндао-Яньтай (в
путь, 2 часа); Яньтай-Циндао ( обратно, 3 часа) 2 часа) Всего 4 часа
Циндао->Цинхай: Циндао-Цинхай (вперед, 6 часов) Циндао-Циндао (обратно, 6 часов) Всего 12 часов

Даны четыре города: Циндао, Шанхай, Яньтай и Цинхай. Учитывая ваш город x, пусть f(i) — кратчайший путь из города i в город x плюс кратчайший путь из города x в город i и найдите максимальное значение f(i).
Теперь x — это Циндао. я могу быть Шанхай, Яньтай, Цинхай
f(Шанхай)=9
f(yt)=4
f(qh)=12

max{f} = max(f(sh), f(yt), f(qh)) = 12

//Это просто евангелие обсессивно-компульсивного расстройства qwq

Надо полагать, видя это, каждый может иметь небольшое прозрение в своем сердце, и я буду говорить об этом подробно;

Каково так называемое максимальное значение поиска кратчайшего пути? Вот вам еще один пример:

Предположим, что x в этом вопросе считается равным 5;

Остальные четыре очка — 1,2,3,4 соответственно. Среди них 1->2, 1->3, 3->4, 2->5, 4->5, 1, 2, 3, 4 я найду с помощью графика, сформированного на основе только что полученной информации. Точка кратчайший путь от каждой точки до 5 точек, сложите их суммы и, наконец, выберите максимальное значение из 4 сумм, полученных в результате сложения.

//Похоже, что кратчайший путь и максимальное значение не конфликтуют.К сожалению, в то время я хотел быть лысым, но в итоге для решения этой проблемы применил очень неуклюжую и бесполезную операцию чистой релаксации.            

 Тогда поразмыслить над этим вопросом в принципе не составляет никакого труда, достаточно использовать конструкцию обратного ребра для выполнения дейкстры. В коде много маленьких хитростей.

#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#include <map>
#include <vector>

const int N = 100005;

struct EDGE {
    int v, w, next;
} e[2][N << 1];

int head[2][N], tot[2] = {1, 1};//为啥要建立二维数组呢?是不是很新奇
//因为正反向建边是完全不同的,要两次来记录,用二维数组较为方便,简洁。
void add(int u, int v, int w, int opt) {//因为反向建边说明我们要建两次
    e[opt][tot[opt]].v = v;//opt就是记录我们是正向建边,还是反向建边
    e[opt][tot[opt]].w = w;
    e[opt][tot[opt]].next = head[opt][u];
    head[opt][u] = tot[opt] ++;
}

struct Node {
    int pos, dis;
    
    Node() {};

    Node(int pos, int dis): pos(pos), dis(dis) {};

    bool operator < (const Node &x) const {
        return dis > x.dis;
    }
};

int dis[2][N], vis[N];

void dijkstra(int opt, int s) {
    std::priority_queue<Node> q;
    memset(dis[opt], 0x3f, sizeof dis[opt]);
    memset(vis, 0, sizeof vis);
    dis[opt][s] = 0;
    q.push(Node(s, 0));
    while (!q.empty()) {//比普通的dijkstra就多了一个opt,就多了一个两种方向的建边而已
        Node f = q.top();
        q.pop();
        int u = f.pos;
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[opt][u]; i; i = e[opt][i].next) {
            int v = e[opt][i].v;
            int w = e[opt][i].w;
            if (!vis[v] && dis[opt][v] > dis[opt][u] + w) {
                dis[opt][v] = dis[opt][u] + w;
                q.push(Node(v, dis[opt][v]));
            }
        }
    }
}

int main() {
    // freopen("/Users/chant/in.txt", "r", stdin);
    int n, m, x;
    std::cin >> n >> m >> x;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;
        add(u, v, w, 0);
        add(v, u, w, 1);
    }
    dijkstra(0, x);
    dijkstra(1, x);
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = std::max(ans, dis[0][i] + dis[1][i]);
    }
    std::cout << ans << '\n';
    return 0;
}

Резюме: Сложность этого вопроса заключается в указанном выше минимальном и максимальном значении, а также в хитроумном использовании выбора для построения прямого и обратного края.Метод оптимального решения довольно странный.

Творить непросто, пожалуйста, не занимайтесь проституцией www! Прошу автора трижды + внимание! Спасибо!

Je suppose que tu aimes

Origine blog.csdn.net/2301_76331300/article/details/131597942
conseillé
Classement