2

私は現在Codechefで問題に取り組んでいます。あなたはここで問題の声明を見つけることができます: 配達の少年

要するに、問題は、からへnの最短経路の時間をクエリするように要求することです。私の解決策は、すでに。があった場合に備えて、結果をにキャッシュしてプラスで使用することです。残念ながら、私は何度も手に入れました、そして私はそれをより速くするためのより良い方法を見つけることができませんでした。私は正しい方向に進んでいるのだろうか?または、この問題に対してより良いアルゴリズムがありますか?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最短経路アルゴリズムを試して、各2つのノード間の最短経路を事前に計算しましたか?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

実際、この場合、フロイド-ワーシャルのアルゴリズムはダイクストラのアルゴリズムよりも優れています。ダイクストラの複雑さはO(m * n ^ 2)であり、この問題ではMはNよりもはるかに高いため、フロイドのO(n ^ 3)時間計算量-ウォーシャルの方が優れています。

于 2012-08-02T13:32:51.033 に答える