【PAT甲级 图单源最短路径 C++】1030 Travel Plan (30 分)

Dijkstra邻接表

# include <iostream>
# include <vector>
# include <algorithm>

using namespace std;

const int INF = 0xffffff;
struct ArcNode{
    
    
    int v;
    int distance, cost; // 记录两种边权,cost为第二标尺
};

// 顶点编号从0 - N-1
int N, M; // 顶点数、边数
int S, D; // 起点、终点

vector<ArcNode> G[510];
int dist[510]; // 最短路径长度
int cost[510]; // 最少路径花费
bool vis[510];
vector<int> pre(510); // 打印路径

void Dijkstra(int s){
    
    
    fill(dist, end(dist), INF);
    fill(cost, end(cost), INF);
    fill(vis, end(vis), false);
    for(int i = 0;i < N;++i) pre[i] = i;
    dist[s] = 0;
    cost[s] = 0;

    for(int i = 0; i < N ;++i){
    
    
        int u = -1;
        int MIN = INF;
        for(int j = 0; j < N ;++j){
    
    
            if(vis[j] == false && dist[j] < MIN){
    
    
                u = j;
                MIN = dist[j];
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(ArcNode next: G[u]){
    
    
            if(vis[next.v] == false){
    
    
                if(dist[u] + next.distance  < dist[next.v]){
    
    
                    dist[next.v] = dist[u] + next.distance;
                    cost[next.v] = cost[u] + next.cost;
                    pre [next.v] = u; 
                } 
                else
                if(dist[u] + next.distance == dist[next.v]){
    
    
                    // 不要为了偷懒写min函数了
                    if(cost[u] + next.cost < cost[next.v]){
    
    
                        cost[next.v] = cost[u] + next.cost;
                        pre [next.v] = u; // 第二标尺更小的时候最优路径也要更新,用min函数就没更新,会错。
                    }
                }
            }
        }
    }
}

void printPATH(int v){
    
    
    if(v == S){
    
    
        cout << S << " ";
        return;
    }

    printPATH(pre[v]);
    cout << v << " ";

}

int main(){
    
    
    cin >> N >> M >> S >> D;
    for(int i = 0;i < M;++i){
    
    
        int C1, C2, d, c;
        cin >> C1 >> C2 >> d >> c;
        G[C1].push_back({
    
    C2, d, c});
        G[C2].push_back({
    
    C1, d, c});
    }
    Dijkstra(S);
    printPATH(D);
    cout << dist[D] << " " << cost[D] << endl;

    return 0;
}


Dijkstra + DFS邻接表

# include <iostream>
# include <vector>
# include <algorithm>

using namespace std;

const int INF = 0xffffff;
struct ArcNode{
    
    
    int v;
    int distance, cost; // 记录两种边权,cost为第二标尺
};

// 顶点编号从0 - N-1
int N, M; // 顶点数、边数
int S, D; // 起点、终点

vector<ArcNode> G[510];
int dist[510]; // 最短路径长度
bool vis[510];
vector<int> pre[510]; // 记录多个最短路径,用来在DFS中计算最少花费的最短路径(不需要初始化)

void Dijkstra(int s){
    
    
    fill(dist, end(dist), INF);
    fill(vis, end(vis), false);
    // for(int i = 0;i < N;++i) pre[i] = i; pre不需要初始化
    dist[s] = 0;

    for(int i = 0; i < N ;++i){
    
    
        int u = -1;
        int MIN = INF;
        for(int j = 0; j < N ;++j){
    
    
            if(vis[j] == false && dist[j] < MIN){
    
    
                u = j;
                MIN = dist[j];
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(ArcNode next: G[u]){
    
    
            if(vis[next.v] == false){
    
    
                if(dist[u] + next.distance  < dist[next.v]){
    
    
                    dist[next.v] = dist[u] + next.distance;
                    // 因为pre[v]是vector,有多个前驱,所以当遇到更短的最短路径时,需要清空;
                    // 但是在只用Dijkstra的方法中,pre只是单纯的数组,pre[v]只是个int,所以直接赋值覆盖即可
                    pre [next.v].clear(); 
                    pre [next.v].push_back(u); 
                } 
                else
                if(dist[u] + next.distance == dist[next.v]){
    
    
                    pre [next.v].push_back(u); 
                }
            }
        }
    }
}

vector<int> path, tempPath;
int minSumCost = INF; // 记得初始化啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
void DFS(int v){
    
    
    if(v == S){
    
    
        tempPath.push_back(S);
      
        int sumcost = 0;
        // 似乎用Dijkstra+DFS和邻接表算边权很复杂……搞了我好久……(+DFS更适合邻接矩阵)
        for(int i = tempPath.size() - 1; i > 0 ;--i){
    
     
            int id = tempPath[i], idnext = tempPath[i-1]; 
            // 因为是邻接表而不是矩阵所以不能直接sumcost += G[id][idnext].cost;
            // REALidnext是顶点idnext在邻接表中的索引
            for(int REALidnext = 0;REALidnext < G[id].size();++REALidnext)
                if(G[id][REALidnext].v == idnext)
                    sumcost += G[id][REALidnext].cost;
        }
        if(sumcost < minSumCost){
    
    
            minSumCost = sumcost;
            path = tempPath;
        }
        
        tempPath.pop_back();
        return;
    }
    tempPath.push_back(v);
    // 搜索v的所有前驱(岔路口)
    for(int u: pre[v])
        DFS(u);
    tempPath.pop_back();
}

int main(){
    
    
    cin >> N >> M >> S >> D;
    for(int i = 0;i < M;++i){
    
    
        int C1, C2, d, c;
        cin >> C1 >> C2 >> d >> c;
        G[C1].push_back({
    
    C2, d, c});
        G[C2].push_back({
    
    C1, d, c});
    }
    Dijkstra(S);
    DFS(D);
    for(int i = path.size()-1;i>=0;i--)
        cout << path[i] << " ";
    cout << dist[D] << " " << minSumCost << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/MYMarcoreus/article/details/113808548