PAT最短路徑問題簡單總結

在PAT甲級真題目錄中,涉及到最短路經問題求解的有1003、1018、1030、1087、1111。

一般來說,可以用最短路徑算法(dijkstra、SPFA等)加上DFS進行求解。

我一般用這些數據結構:

struct node{
    int v;//與該地點相連的地點的序號
    int cost;//兩個地點之間的距離
    //...由題意確定需要增加變量
    node(int v,int cost):v(v),cost(cost){ }
}
vector<node> g[maxn];//鄰接表的形式存儲圖
vector<int> pre[maxn];//在求解最短路徑時記錄前序節點,用於後續的dfs求解
int d[maxn];//最短路算法中的d
int vis[maxn];//是否訪問過
vector<int> path,temppath;//在dfs中記錄路徑
//...視情況增加需要的變量

1.在main函數中依次讀入點數、邊數、起點、終點;再讀入邊的信息,完成輸入。

2.求解最短路徑,當權值爲非負時,使用dijkstra O(n^2),當權值有負但沒有負圈時可以用SPFA O(kE),SPFA能檢測負圈,不過PAT上的數據沒那麼難,dijkstra通常都能在規定時間內求出解,不過我還是喜歡用SPFA。

如果題目要求輸出路徑的話,在進行鬆弛操作的時候,需要記錄下節點的前序節點

if(d[v]>d[cur]+cost){
    d[v]=d[cur]+cost;
    pre[v].clear();
    pre[v].push_back(cur);
    //...
}
else if(d[v]==d[cur]+cost){
    pre[v].push_back(cur);
}
//如果題目上寫:若存在多條長度相同的最短路徑,輸出耗時最短的路徑(保證唯一)
//那麼可以再增加一個變量 int weight[maxn]
//因爲路徑唯一,可以直接用 int pre[maxn]來記錄前序節點,就不需要用vector了,後續的dfs也省事
if(d[v]>d[cur]+cost){
    d[v]=d[cur]+cost;
    weight[v]=weight[cur]+time;
    pre[v]=cur;
    //...
}
else if(d[v]==d[cur]+cost&&weight[v]>weight[cur]+time){
    weight[v]=weight[cur]+time;
    pre[v]=cur;
}

3.求解需要輸出的路徑,由於最短路徑不唯一,需要根據題目要求來輸出,這時候一般就用dfs。

void dfs(int cur){//因爲pre數組記錄了前序節點,所以從後往前找
    temppath.push_back(cur);
    if(cur==s){//當前節點爲開始節點
        //這時temppath已經記錄下了一條完整的路徑,根據題目要求來
        if(temppath符合要求)
            path=temppath;
    }
    else{
        for(int i=0;i<pre[cur].size();i++)
            dfs(pre[cur][i]);
    }
    temppath.pop_back();//別忘了回到之前狀態
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章