在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();//別忘了回到之前狀態
}