В настоящее время я работаю над упражнением vjudge, и мне не удается понять, в чем проблема с выполнением этого упражнения.
Краткое описание проблемы:
Учитывая ориентированный граф с n
узлами (где n
не более 500
), матрицу смежности всех расстояний между ними и список n
узлов, определяющий порядок удаления узлов из этого графа, выполните следующий процесс:
Перебирайте список узлов, которые нужно удалить. На каждом этапе к ответу (который начинается с 0
) добавляется сумма кратчайших расстояний между каждой упорядоченной парой различных неудаленных узлов графа. Затем удалите текущий узел в списке из графа, что может изменить кратчайшие расстояния для последующих итераций. В конце выведите ответ.
Полная постановка задачи:
После многих лет планирования Галактическая Империя построила планетарную крепость Джеонозис, идеальную тюрьма для лидеров восстания и особое место, отведенное для злого Люка Скайуокера. Однако, как показали неудачи Звезды Смерти I и II, крепость не идеальна и злой Альянс повстанцев планирует использовать слабость, обнаруженную в окружающих башнях связи. Джеонозис.
Чтобы реализовать свои коварные планы, Альянс повстанцев украл карту со структурой крепости. На Джеонозисе есть коммуникационный комплекс, состоящий из n башен. Каждая пара башен комплекса соединены линиями электропередачи, которые отправляют сообщения по затратам энергии. Повстанцы хотят построить корабль «Изгой-два», чтобы разрушить крепость и спасти ее пленников. К Чтобы добиться этого, им придется разрушить все башни крепости. Они обнаружили, что сила необходимое для разрушения башни равно сумме минимальной энергии, необходимой для отправки сообщения между каждой парой крепостных башен либо прямо, либо опосредованно через другие башни.
Обратите внимание: как только башня разрушена, она перестает учитываться в этой формуле.
С другой стороны, командир Разбойника-Два очень капризен и хочет уничтожить башни в заданном порядке. Зная информацию о башнях связи на Джеонозисе и порядок, в котором каждая башня будет разрушена, можете ли вы сказать, какая мощность необходима для Разбойника-Два? выполнить свою миссию?
Для матриц n < 4 у меня нет проблем, но моя проблема возникает с матрицами, такими что n >= 4.
Я считаю, что первый цикл, с одной стороны, не нужен, поскольку у меня уже есть матрица стоимости графа. Во-вторых, это может быть причиной моего неправильного результата.
Вот ссылка на упражнение: Геонозис (UVA-13211)
#include <iostream>
#include <vector>
#include <limits>
using namespace std;
const int INFTY = numeric_limits<int>::max(); // Use numeric_limits for infinity
// Graph representing the Geonosis Map.
struct Graph {
vector<vector<int>> costo;
explicit Graph(int n) {
costo.resize(n, vector<int>(n));
}
};
// Floyd-Warshall implementation APSP.
void APSP(const Graph& geonosis, vector<vector<int>>& dist) { // Pass dist by reference (improves space complexity=
unsigned long n = geonosis.costo.size();
// Initialize dist with the given graph's costo
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (i == j) {
dist[i][j] = 0;
} else if (geonosis.costo[i][j] != 0) {
dist[i][j] = geonosis.costo[i][j];
}
}
}
// Compute all pair shortest paths using Floyd-Warshall algorithm
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (geonosis.costo[i][k] != INFTY && geonosis.costo[k][j] != INFTY) {
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
}
}
int solve(int t) {
while (t--) {
int n;
unsigned long long res = 0;
cin >> n;
cin.ignore(); // to ignore the newline after the number.
// to create my case matrix and return the shortest path to destroy all towers.
Graph geonosis(n);
vector<int> destOrder(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> geonosis.costo[i][j];
}
}
// we make a sequence that stores the dest. order for the case.
for (int i = 0; i < n; ++i) {
cin >> destOrder[i];
}
vector<vector<int>> dist(n, vector<int>(n, INFTY));
APSP(geonosis, dist);
// once we finish executing APSP, dist matrix has the shortest path from each vertex i to each vertex j while i != j.
// we want to keep track of the towers that have been destroyed
vector<bool> destroyed(n, false);
for (int d = 0; d < n; ++d) {
int currentTower = destOrder[d];
unsigned long long currentSum = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (!destroyed[i] && !destroyed[j] && dist[i][j] != INFTY) {
currentSum += dist[i][j];
}
}
}
destroyed[currentTower] = true;
// Add the current sum to the total sum
res += currentSum;
}
// Print the total sum of all shortest paths
cout << res << endl;
}
return 0;
}
int main() {
int t;
cin >> t;
solve(t);
return 0;
}
Я попытался реализовать это упражнение с использованием алгоритма Данцига для расчета APSP, но оно по-прежнему возвращает тот же результат. Я даже не могу точно определить проблему во время отладки.
После многих лет планирования Галактическая Империя построила планетарную крепость Джеонозис. Я знаю, что вы новичок, но вам следует точно писать о том, какая у вас проблема, а не рассказывать истории. Причина, по которой рассказывать истории вместо того, чтобы переходить к вопросу, неразумно, заключается в том, что многие из тех, кто мог бы вам помочь, просто не захотят тратить свое время на чтение подобных вещей. Если проблема в реализации алгоритма Флойда-Уоршалла, это все, что вам нужно упомянуть.
@PaulMcKenzie Я добавил формулировку проблемы к вопросу, чтобы избежать гниения ссылок. Я отредактировал более краткое техническое описание проблемы. (Проблема не в реализации соглашения Флойда-Уоршалла.)
Проблема с вашим кодом заключается в том, что вы запускаете Floyd-Warshall только один раз и не обрабатываете удаление узлов должным образом. Когда узел уничтожается, вы игнорируете только пути, которые начинаются или заканчиваются в узле, не учитывая тот факт, что кратчайший путь между другими парами узлов, возможно, уже использовал ребро, проходящее через разрушенный узел. Фактически, единственный способ справиться с удалением узла — это перестроить всю матрицу кратчайших путей, что каждый раз слишком медленно.
Вместо этого обратите внимание, что порядок выполнения операций, подразумеваемый формулировкой задачи, ведет вас к неэффективному решению. Если вы проходите по уничтоженным узлам в обратном порядке, то каждый раз вы добавляете в граф новый узел, а не уничтожаете узел, поэтому обновление кратчайших путей можно выполнить за O(N^2).
Вот рабочее решение:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int t, n;
for (std::cin >> t; t--;) {
std::cin >> n;
std::vector<std::vector<int>> cost(n, std::vector<int>(n));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
std::cin >> cost[i][j];
std::vector<int> order(n);
for (int& o : order) std::cin >> o;
long long totalPower = 0;
std::vector<bool> active(n);
for (int i = n - 1; i >= 0; --i) {
active[order[i]] = true;
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k) {
cost[j][k] = std::min(cost[j][k], cost[j][order[i]] + cost[order[i]][k]);
if (active[j] && active[k]) totalPower += cost[j][k];
}
}
std::cout << totalPower << '\n';
}
}
Вы даже не представляете, как сильно вы мне помогли. Я новичок в вопросах переполнения стека, поэтому извините за длину вопроса, но я искренне ценю ваше потраченное время.
@str8 Рад помочь. :)
Пробовали ли вы отлаживать свою программу? Например, используя отладчик для пошагового выполнения кода, отслеживая переменные и их значения, чтобы увидеть, что происходит на самом деле?