刚开始用Floyd Warshall算法求每对节点的最短路径,时间复杂度为v^3,空间上用的是邻接矩阵,结果超时。总结:这种方法适合于密集图。
后来考虑用dijsktra算法求单源最短路径,但是heap实现起来比较复杂,还得多个时间复杂度为O(logn)的decreasemin方法。网上看解题报告,看到了Shortest_Path_Faster_Algorithm。于是去wikipedia(http://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm)上查看。思路很简单,据称最坏时间复杂 度非常坏,但在稀疏图中的时间复杂度好,为O(E),并且可以应用在(无负环)的负数权值图中。于是照着伪代码实现了。效果非常好。之后照着wikipedia后面介绍的优化方法写了下,也很简单,也有时间上的提升。
TASK: butter LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.000 secs, 5868 KB] Test 2: TEST OK [0.000 secs, 5868 KB] Test 3: TEST OK [0.000 secs, 5868 KB] Test 4: TEST OK [0.000 secs, 5868 KB] Test 5: TEST OK [0.000 secs, 5868 KB] Test 6: TEST OK [0.000 secs, 5868 KB] Test 7: TEST OK [0.011 secs, 5868 KB] Test 8: TEST OK [0.022 secs, 5868 KB] Test 9: TEST OK [0.043 secs, 5868 KB] Test 10: TEST OK [0.043 secs, 5868 KB] All tests OK.附注:一块草地上可以有不止一头牛。
代码如下:
/* ID: thestor1 LANG: C++ TASK: butter */ #include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <cassert> #include <string> #include <algorithm> #include <stack> #include <set> #include <queue> using namespace std; const int P = 800; const int infinity = 180000; int dis[P][P]; struct Edge{ int v; int w; Edge *next; Edge(int v, int w) { this->v = v; this->w = w; this->next = NULL; } }; struct Vertex{ int u; Edge *adj; Vertex(int i) { this->u = i; adj = NULL; } }; void spfa(const int s, const int p, Vertex **vertexes) { for(int i = 0; i < p; ++i) { dis[s][i] = infinity; } dis[s][s] = 0; deque<int> que; bool onQueue[P]; memset(onQueue, false, p * sizeof(bool)); que.push_back(s); onQueue[s] = true; while(!que.empty()) { int u = que.front(); que.pop_front(); onQueue[u] = false; for(Edge *e = vertexes[u]->adj; e != NULL; e = e->next) { if(dis[s][u] + e->w < dis[s][e->v]) { dis[s][e->v] = dis[s][u] + e->w; if(!onQueue[e->v]) { if(que.empty() || dis[s][e->v] < dis[s][que.front()]) { que.push_front(e->v); } else { que.push_back(e->v); } onQueue[e->v] = true; } } } } } int main() { FILE *fin = fopen ("butter.in", "r"); FILE *fout = fopen ("butter.out", "w"); //freopen("log_1.txt", "w", stdout); int n, p, c; fscanf(fin, "%d%d%d", &n, &p, &c); Vertex **vertexes = new Vertex*[p]; for(int i = 0; i < p; ++i) { vertexes[i] = new Vertex(i); } vector<int> dests; for(int i = 0; i < n; ++i) { int dest; fscanf(fin, "%d", &dest); dests.push_back(dest - 1); } for(int i = 0; i < c; ++i) { int p1, p2, d; fscanf(fin, "%d%d%d", &p1, &p2, &d); Edge *euv = new Edge(p2 - 1, d); euv->next = vertexes[p1 - 1]->adj; vertexes[p1 - 1]->adj = euv; Edge *evu = new Edge(p1 - 1, d); evu->next = vertexes[p2 - 1]->adj; vertexes[p2 - 1]->adj = evu; } for(int i = 0; i < n; ++i) { spfa(dests[i], p, vertexes); } int mindis = -1; for(int i = 0; i < p; ++i) { int sum = 0; for(int j = 0; j < n; ++j) { sum += dis[dests[j]][i]; //fprintf(stdout, "%d->%d: %d, ", i, dests[j], dis[dests[j]][i]); } //fprintf(stdout, "\n%d: %d\n\n", i, sum); if(mindis < 0 || sum < mindis) { mindis = sum; } } fprintf(fout, "%d\n", mindis); return 0; }