gpt4 book ai didi

algorithm - 查询n次时如何改进Dijkstra算法?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:31:45 26 4
gpt4 key购买 nike

我目前正在 Codechef 处理一个问题.您可以在此处找到问题陈述: Delivery Boy

简而言之,问题是要求查询 n 次从 startend 的最短路径。我的解决方案是将 Dijsktrapriority_queue 一起使用,并将结果缓存到 hash_map 中,以防我们已经有了一个 start .不幸的是,我多次遇到 time limit exceed 并且我找不到更好的方法来让它更快。我想知道我是否在正确的轨道上?或者有更好的算法来解决这个问题?

顺便说一句,由于比赛仍在进行中,请不要发布任何解决方案。一个提示对我来说绰绰有余。谢谢。

这是我的尝试:

#ifdef __GNUC__
#include <ext/hash_map>
#else
#include <hash_map>
#endif

#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <utility>
#include <stack>
#include <deque>
#include <queue>
#include <fstream>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>

using namespace std;

#ifdef __GNUC__
namespace std {
using namespace __gnu_cxx;
}
#endif


const int MAX_VERTICES = 250;
const int INFINIY = (1 << 28);
int weight[MAX_VERTICES + 1][MAX_VERTICES + 1];
bool visited_start[MAX_VERTICES + 1] = { 0 };

struct vertex {
int node;
int cost;

vertex(int node = 0, int cost = 0)
: node(node), cost(cost) {
}

bool operator <(const vertex& rhs) const {
return cost < rhs.cost;
}

bool operator >(const vertex& rhs) const {
return cost > rhs.cost;
}
};

hash_map<int, vector<vertex> > cache;
typedef priority_queue<vertex, vector<vertex>, greater<vertex> > min_pq;

vector<vertex> dijkstra_compute_path(int start, int n) {
min_pq pq;
vector<vertex> path;
vector<int> visited(n, 0);
int min_cost = 0;
int better_cost;
vertex u;

for (int i = 0; i < n; ++i) {
path.push_back(vertex(i, INFINIY));
}

path[start].cost = 0;
pq.push(vertex(start, path[start].cost));

while (!pq.empty()) {
// extract min cost
u = pq.top();
pq.pop();

// mark it as visited
visited[u.node] = 1;

// for each vertex v that is adjacent to u
for (int v = 0; v < n; ++v) {
// if it's not visited, visit it
if (visited[v] == 0) {
better_cost = path[u.node].cost + weight[u.node][v];
// update cost
if (path[v].cost > better_cost) {
path[v].cost = better_cost;
pq.push(vertex(v, path[v].cost));
}
}
}
}

return path;
}

void check_in_cache(vector<vertex>& path, int start, int no_street) {
if (visited_start[start] == 0) {
path = dijkstra_compute_path(start, no_street);
cache.insert(make_pair(start, path));
visited_start[start] = 1;
}
else {
path = cache[start];
}
}

void display_cost(int stop_at_gas_cost, int direct_cost) {
printf("%d ", stop_at_gas_cost);
if (stop_at_gas_cost > direct_cost) {
printf("%d\n", stop_at_gas_cost - direct_cost);
}
else {
printf("0\n");
}
}

void handle_case_one() {
int no_scenario;
int dummy;
int s, g, d;

scanf("%d", &dummy);
scanf("%d", &no_scenario);
for (int i = 0; i < no_scenario; ++i) {
scanf("%d %d %d", &s, &g, &d);
printf("0 0\n");
}
}

void inout_delivery_boy() {
int no_street;
int no_scenario;
int restaurant;
int gas_station;
int destination;
int stop_at_gas_cost;
int direct_cost;
vector<vertex> direct;
vector<vertex> indirect;
vector<vertex> d;
int c;

scanf("%d", &no_street);
if (no_street == 1) {
handle_case_one();
return;
}

for (int x = 0; x < no_street; ++x) {
for (int y = 0; y < no_street; ++y) {
scanf("%d", &c);
weight[x][y] = c;
}
}

for (int i = 0; i < no_street; ++i) {
d.push_back(vertex(i, INFINIY));
}

scanf("%d", &no_scenario);
for (int i = 0; i < no_scenario; ++i) {
scanf("%d %d %d", &restaurant, &gas_station, &destination);

// check in cache
check_in_cache(direct, restaurant, no_street);
check_in_cache(indirect, gas_station, no_street);

// calculate the cost
stop_at_gas_cost = direct[gas_station].cost + indirect[destination].cost;
direct_cost = direct[destination].cost;

// output
display_cost(stop_at_gas_cost, direct_cost);
}
}

void dijkstra_test(istream& in) {
int start;
int no_street;
int temp[4] = { 0 };
vector<vertex> path;

in >> no_street;
for (int x = 0; x < no_street; ++x) {
for (int y = 0; y < no_street; ++y) {
in >> weight[x][y];
}
}

// arrange
start = 0;
temp[0] = 0;
temp[1] = 2;
temp[2] = 1;
temp[3] = 3;

// act
path = dijkstra_compute_path(start, no_street);

// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}

// arrange
start = 1;
temp[0] = 1;
temp[1] = 0;
temp[2] = 2;
temp[3] = 4;

// act
path = dijkstra_compute_path(start, no_street);

// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}

// arrange
start = 2;
temp[0] = 2;
temp[1] = 1;
temp[2] = 0;
temp[3] = 3;

// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}

// arrange
start = 3;
temp[0] = 1;
temp[1] = 1;
temp[2] = 1;
temp[3] = 0;

// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
}

int main() {
// ifstream inf("test_data.txt");
// dijkstra_test(inf);
inout_delivery_boy();
return 0;
}

最佳答案

请注意问题中 N 很小。你试过弗洛伊德最短路径算法来预先计算每两个节点之间的最短路径吗?会耗费O(N^3)的时间,也就是问题中的250^3=15625000,应该很容易在1秒内跑完。然后您可以在 O(1) 中回答每个查询。

弗洛伊德简介:

http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm

ps:我认为缓存的 dijstra 对整个测试用例的最大运行时间也是 O(N^3)。但是你实现缓存的方式会花费更多不必要的时间在内存复制上,这可能会导致 TLE。只是一个猜测。

关于algorithm - 查询n次时如何改进Dijkstra算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11772554/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com