2

我目前正在Codechef解决一个问题。您可以在此处找到问题说明: 送货员

简而言之,问题是要求查询从 a到na 的最短路径的时间。我的解决方案是使用with plus 将结果缓存到 a中,以防我们已经有一个. 不幸的是,我得到了很多次,我找不到更好的方法来让它更快。我想知道我在正确的轨道上吗?或者有更好的算法来解决这个问题?startendDijsktrapriority_queuehash_mapstarttime 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;
}
4

2 回答 2

4

请注意问题中的 N 很小。您是否尝试过 Floyd 最短路径算法来预先计算每两个节点之间的最短路径?它将花费 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。只是一个猜测。

于 2012-08-02T07:37:29.333 回答
2

事实上,在这种情况下,Floyd-Warshall 的算法比 Dijkstra 的算法要好,Dijkstra 的复杂度是 O(m*n^2),在这个问题中,M 远高于 N,所以 Floyd-的 O(n^3) 时间复杂度华夏尔更好。

于 2012-08-02T13:32:51.033 回答