在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();//别忘了回到之前状态
}