PAT A中30分答题常考题
1、Dijkstra算法+DFS(重点)
(无负边权)单源最短路径问题万能通法,可以回溯路径,选取多条件最优路径
以在最短路径前提下的最小花费问题为例(其余条件根据题目变通)
在主函数中直接 Dijkstra(start); DFS(end);即可,path记录的就是有约束下的最短路径
int G[maxN][maxN]; //记录两点间距离
int C[maxN][maxN]; //记录两点间花费
int start; //记录起点
int d[maxN]; //记录从起点到各点的最短路径
int visit[maxN]={0};
vector<int> pre[maxN]; //记录可能的先驱结点
int inf=1000000000;
vector<int> path,temppath;
int Mincost=inf;
void DFS(int index){
temppath.push_back(index);
if(index==start){
int cost=0;
for(int i=temppath.size()-1;i>0;i--){
cost+=C[temppath[i]][temppath[i-1]];
}
if(cost<Mincost) path=temppath;
temppath.pop_back();
return;
}
for(auto it:pre[index]){
DFS(it);
}
temppath.pop_back();
}
void dijkstra(int s){
fill(d,d+maxN,inf);
d[s]=0;
for(int i=0;i<N;i++){
int u=-1;Min=inf;
for(int j=0;j<N;j++){
if(visit[j]==0&&d[j]<Min){
u=j;
Min=d[j];
}
}
if(u==-1) return;
visit[u]=1;
for(int v=0;v<N;v++){
if(visit[v]==0&&G[u][v]!=inf){
if(d[u]+G[u][v]<d[v]){
d[v]=d[u]+G[u][v];
pre[v].clear();
pre[v].push_back(u);
}else if(d[u]+G[u][v]==d[v]){
pre[v].push_back(u);
}
}
}
}
}
2、Floyd算法
用以解决全源最短距离问题,当题目中结点个数在200这个量级时,可以优先考虑Floyd算法,因为算法非常简单简捷
在主函数中读取完后直接使用 Floyd(); 即可
int d[maxN][maxN]; //用以记录两点间距离 (在主函数中先填充inf,后读取数值)
int inf=1000000000;
int N; //结点数
void Floyd(){
for(int k=0;k<N;k++){ //记的时候只需记,中间结点在最外层
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(d[i][k]!=inf&&d[k][j]!=inf&&d[i][j]>d[i][k]+d[k][j]){
d[i][j]=d[i][k]+d[k][j];
}
}
}
}
}
3、Bellman-Ford算法(暂未考过)
如果有负边权的单源最短距离问题,dijkstra就不适用了
可以了解记一下,也不难
struct node{
int v,dis;
};
int N;
vector<node> Adj[maxN]; //邻接表记录
int d[maxN];
int inf=1000000000;
bool Bellman_Ford(int s){
fill(d,d+maxN,inf);
d[s]=0;
for(int i=0;i<N-1;i++){ //进行N-1次遍历所有边
for(int u=0;u<N;u++){
for(int j=0;j<Adj[u].size();j++){
int v=Adj[u][j].v;
int dis=Adj[u][j].dis;
if(d[v]>d[u]+dis){
d[v]=d[u]+dis;
}
}
}
}
//判断是否有负环 再来1次
for(int u=0;u<N;u++){
for(int j=0;j<Adj[u].size();j++){
int v=Adj[u][j].v;
int dis=Adj[u][j].dis;
if(d[v]>d[u]+dis){
return false;
}
}
}
return true; //所有最短路径已达到最优
}