1. 程式人生 > 實用技巧 >POJ-2387 Til the Cows Come Home

POJ-2387 Til the Cows Come Home

hyh大佬很熱愛學習,他打算偷偷跑回學校學習,為了多學習他希望可以找最快的路線回到學校。
廣州市裡有N個(2 <= N <= 1000)個地鐵站,編號分別為1..N。zzj家在1號地鐵站旁邊,五山站是N號地鐵站。地鐵站之間共有M (1 <= M <= 2000)條雙向路徑。
hyh現在在1號地鐵站,他希望知道到學校最短要多長時間。可以保證hyh能到達學校。忽略hyh在換乘地鐵時需要的等待時間

Sample Input

    5 5
    1 2 20
    2 3 30
    3 4 20
    4 5 20
    1 5 100

Sample Output

    90

Dijkstra演算法思想:主要特點是從起始點開始,採用

貪心演算法的策略,每次遍歷到始點距離最近且未訪問過的頂點的鄰接節點,直到擴充套件到終點為止。 時間複雜度O(n^2),程式碼如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxx = 1005;
int adj[maxx][maxx]; // 鄰接表來儲存圖的資訊
bool found[maxx];  //標記是否訪問過該結點
int t, n;
const int inf = 1 << 29;  //記住不要將最大值設成101等,雖然說題目給的邊的大小是1 ~ 100 但是輸入資料有坑
void init() { // 初始化 for (int i = 1; i <= n ; ++i) { for (int j = 1; j <= n; ++j) { adj[i][j] = inf; } } memset(found, false, n + 1); } void dijkstra() { int dis[n + 1]; for (int i = 1; i <= n; ++i) { dis[i] = adj[n][i]; // 首先對distance陣列進行初始化 我選擇的是從結點n到結點1
// 也可以選擇從結點1到結點n } found[n] = true; for (int i = 1; i <= n; ++i) { int minv = 0, mind = inf; //找到在未被訪問的結點之中的最小的結點 for (int j = 1; j <= n; ++j) { if (found[j]) continue; if (dis[j] < mind) { minv = j; mind = dis[j]; } } for (int j = 1; j <= n; ++j) { if (adj[minv][j] != inf) { dis[j] = min(dis[j], adj[minv][j] + dis[minv]); // 對dis進行更新 } } found[minv] = true; } printf("%d\n", dis[1]); } int main() { scanf("%d%d", &t, &n); init(); for (int i = 0; i < t; ++i) { int from, to, edge; scanf("%d%d%d", &from, &to, &edge); adj[from][to] = adj[to][from] = min(adj[from][to], edge); // 去重邊 } dijkstra(); return 0; }

Floyd演算法思想:(時間複雜度O(N^3),在此題中會超時,寫出來只是供大家學習一下)

1,從任意一條單邊路徑開始。所有兩點之間的距離是邊的權,如果兩點之間沒有邊相連,則權為無窮大。 2,對於每一對頂點 u 和 v,看看是否存在一個頂點 w 使得從 u 到 w 再到 v 比已知的路徑更短。如果是更新它。
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int t, n;
const int maxx = 1005;
int gra[maxx][maxx], path[maxx][maxx];
const int inf = 1 << 29;

void floyd() {
    vector<vector<int> > A(n + 1, vector<int>(n + 1));
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            A[i][j] = gra[i][j];
            path[i][j] = -1;
        }
    }
    for (int v = 1; v <= n; ++v) {
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (A[i][j] > A[i][v] + A[v][j]) {
                    A[i][j] = A[i][v] + A[v][j];
                    path[i][j] = v;
                }
            }
        }
    }
}

int printPath(int v, int w) {
    if (-1 == path[v][w]) {
        return gra[v][w];
    }
    int mid = path[v][w];
    return printPath(v, mid) + printPath(mid, w);
}

int main() {
    scanf("%d%d", &t, &n);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (i != j)
                gra[i][j] = inf;
        }
    }

    for (int i = 0; i < t; ++i) {
        int from, to, edge;
        scanf("%d%d%d", &from, &to, &edge);
        gra[from][to] = gra[to][from] = min(gra[from][to], edge);
    }
    floyd();
    printf("%d\n", printPath(n, 1));
    return 0;
}

相比較可得知Dijkstra演算法更優於Floyd演算法,但是,Dijkstra演算法不能處理負權邊而Floyd可以,一般我們可以觀察題目給出的資料大小來選擇我們解題的演算法。