1. 程式人生 > >1030 Travel Plan (30 分)Dijkstra+DFS應用

1030 Travel Plan (30 分)Dijkstra+DFS應用

題目

A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:
For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

Sample Output:

0 2 3 3 40

解題思路

  題目大意: 有N個城市,每兩個聯通的城市之間,有距離和旅行開銷,問從S城市到D城市的最小開銷是多少。
  解題思路: 先用Dijkstra演算法整理出從s到任意一個結點的最短距離,然後用DFS演算法求所有最短路徑中的最小開銷。


#include<iostream>
#include<vector>
using namespace std;
const int maxv = 510;
const int INF = 1e9 + 10;
int G[maxv][maxv], d[maxv], C[maxv][maxv];// g表示結點各個城市的距離,d表示s到各個結點的距離,c表示s到各個結點的花費 
int n, m, s, dd, mincost = INF;
bool vis[maxv];

vector<int>pre[maxv];

vector<int>temp, path;
// 這個函式的目的是從s開始,算出來s到每一個點的dist 
void Dijkstra(int s)
{
    fill(d, d + maxv, INF);
    d[s] = 0;
    while (1)
    {
        int u = -1, MIN = INF;
        //  
        for (int i = 0; i < n; i++)
        {
            if (!vis[i]&&d[i] < MIN)MIN = d[i], u = i;
        }
        if (u == -1)return;
        vis[u] = true;
        for (int i = 0; i < n; i++)
        {
            if (!vis[i] && G[u][i])// 如果u到i點存在路徑 
            {
                if (d[u] + G[u][i] < d[i]) // 在存在的路徑中,找到比s->i更短的路徑 
                { 
                    d[i] = d[u] + G[u][i];// 更新s->i的最短距離值 
                    pre[i].clear();
                    pre[i].push_back(u);// 更新該路徑的記錄 
                }
                else if (d[u] + G[u][i] == d[i])// 如果該路徑與最小路徑相等,儲存 ,s->i可能存在多條路徑 
                {
                    pre[i].push_back(u);
                }
            }
        }
    }
}

// 深度優先遍歷演算法 找到最低開銷 
void DFS(int v)
{
    if (v == s)// 如果當前訪問結點是開始結點s ,表明深度優先終止 
    {
        temp.push_back(s);
        int tempcost = 0;
        // 計算從s開始所有DFS經過的結點的花銷總和 
        for (int i = temp.size() - 1; i > 0; i--)
        {
            int v = temp[i];
            int u = temp[i - 1];
            tempcost += C[u][v];
        }
        // 如果這個開銷比最小的值,那麼是一個最小開銷的路徑 
        if (tempcost < mincost)
        {
            mincost = tempcost;
            path = temp;//使用path記錄該最小開銷的路徑 
        }
        temp.pop_back();// 該節點已經探測結束,彈出,防止干擾同層次其他節點的訪問 
        return;
    }
    temp.push_back(v);// v加入,表示該節點已經訪問 
    for (int i = 0; i < pre[v].size(); i++)// 訪問v的所有最短路徑鄰接節點 
        DFS(pre[v][i]);
    temp.pop_back();// 該節點已經探測結束,彈出,防止干擾同層次其他節點的訪問 
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &s, &dd);
    for (int i = 0; i < m; i++)
    {
        int c1, c2, dis, cost;
        scanf("%d%d%d%d", &c1, &c2, &dis, &cost);
        G[c1][c2] = G[c2][c1] = dis;
        C[c1][c2] = C[c2][c1] = cost;
    }
    Dijkstra(s);
    DFS(dd);
    for (int i = path.size() - 1; i >= 0; i--)printf("%d ", path[i]);
    printf("%d %d", d[dd], mincost);
    return 0;
}

在這裡插入圖片描述

總結

  該題目需要熟練操作DFS和Dijkstra,其實也不算太難。