1030 Travel Plan(Dijkstra or Dijkstra+DFS)

13 篇文章 0 订阅

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
//迪杰斯特拉
//邻接矩阵版


//Dijkstra版本
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;  //最大顶点数
const int INF = 1000000;
int n, m, st, ed;     //n为顶点数,m为边数,st为起点,ed为终点,G邻接矩阵
int G[maxn][maxn], cost[maxn][maxn];
int d[maxn];        //起点到各个顶点的最短路径长度
int pre[maxn], c[maxn];      //结点的前驱
bool vis[maxn] = {false};       //标记是否访问

void Dijkstra(int s)
{
    fill(d, d + maxn, INF);
    fill(c, c + maxn, INF);
    d[s] = 0;
    c[s] = 0;
    for(int i  = 0; i < n; i++) //记得初始化,初始状态每个节点的前驱为自身
        pre[i] = i;
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = INF;     //使d[u]最小的还未被访问过的顶点的标号   MIN存放最小的d[u]
        for(int j = 0; j < n; j++)       //找到未访问顶点中d[]最小的
        {
            if(vis[j] == false && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
        if(u == -1) return;     //找不到小于INF的d[u],说明剩下的顶点和s不连通
        vis[u] = true;      //标记u已经被访问
        for(int v = 0; v < n; v++)
        {
            if(vis[v] == false && G[u][v] != INF)
            {
                if(G[u][v] + d[u] < d[v])        //以u为中介点可以使d[v]更优
                {
                    d[v] = G[u][v] + d[u];
                    c[v] = cost[u][v] + c[u];
                    pre[v] = u;
                }
                else if(G[u][v] +d[u] == d[v])
                {
                    if(cost[u][v] + c[u] < c[v])
                    {
                        c[v] = cost[u][v] + c[u];
                        pre[v] = u;
                    }
                }
            }
        }
    }
}


void DFS(int v)   //输出最短路径
{
    if(v == st)
    {
        printf("%d ", st);
        return;
    }
    DFS(pre[v]);
    printf("%d ", v);
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &st, &ed);    //n为顶点数,m为边数,s为起点
    int u, v;
    fill(G[0], G[0] + maxn * maxn, INF);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d", &u, &v);
        scanf("%d%d", &G[u][v], &cost[u][v]);
        G[v][u] = G[u][v];
        cost[v][u] = cost[u][v];
    }
    Dijkstra(st);
    DFS(ed);
    printf("%d %d\n", d[ed], c[ed]);  //最短距离和花费
	return 0;
}

Dijkstra+DFS方法
基本思想:用临时数组保存下来所有的最短路径,对这些最短路径统一计算点权,边权等条件,即第二甚至第三标尺,得到最终结果
1.使用Dijkstra算法记录所有最短路径,每个节点会存在多个前驱节点,定义vector数组pre,保存每个节点的前驱节点
2.从最后一个节点开始倒序DFS遍历生成树(每个节点的前驱节点可能有多个,遍历的过程可能会形成一颗递归树),每次到达叶子节点就是一条最短路径,对这条路径计算需要的条件,如果得到更优的解则覆盖

//Dijkstra + DFS版本
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;       //最大顶点数
const int INF = 1000000;
int n, m, st, ed;
int G[maxn][maxn], cost[maxn][maxn];    //n为顶点数,m为边数,st为起点,ed为终点,G邻接表,cost花费矩阵
int d[maxn], minCost = INF;             //起点到各个顶点的最短路径长度
bool vis[maxn] = {false};               //标记是否访问
vector<int> pre[maxn];
vector<int> path, tempPath;
void Dijkstra(int s)
{
    // 初始化
    fill(d, d + maxn, INF);
    d[s] = 0;
    //Dijkstra+DFS方式时,pre不需要初始化
    //for(int i  = 0; i < n; i++) 
       // pre[i] = i;
    // n次循环
    for(int i = 0; i < n; i++)
    {
        int u = - 1, MIN = INF;
        for(int j = 0; j < n; j++)
        {
            if(vis[j] == false && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
        if(u == -1) return;
        //vis[u] == true;    //!!!!!
        vis[u] = true;      //标记已访问
        for(int v = 0; v < n; v++)
        {
            if(vis[v] == false && G[u][v] != INF)
            {
                if(G[u][v] + d[u] < d[v])   //以u为中介点使d[v]更小
                {
                    d[v] = G[u][v] + d[u];
                    pre[v].clear();         //清空前驱
                    pre[v].push_back(u);    //u是v的前驱
                }
                else if(G[u][v] + d[u] == d[v])     //找到不止一条最短路径,则到达v不止一个前驱,将u加入到v的前驱
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}



void DFS(int v)     //v为当前结点,寻找以v为起点的路径
{	
	//递归边界
    if(v == st)     //递归边界,到达叶子结点(路径起点) 递归边界:v是路径起点st的时候
    {
        tempPath.push_back(v);	//将起点st加入到tempPath的最后面
        int tempCost = 0;       //记录花费之和(计算第二标尺)
        for(int i = tempPath.size() - 1; i > 0; i--)    //倒着访问
        {
            int id = tempPath[i], idnext = tempPath[i - 1];
            tempCost += cost[id][idnext];       //增加id->idnext的边权
        }
        if(tempCost < minCost)      //当前路径的边权和更小
        {
            minCost = tempCost;
            path = tempPath;
        }
        tempPath.pop_back();	//将刚加入的结点删除
        return;
    }
    //递归式
    tempPath.push_back(v);	//将当前访问结点v加入到tempPath的最后面
    for(int i = 0; i < pre[v].size(); i++)	//递归v的前驱节点
        DFS(pre[v][i]);     //倒序遍历该节点的所有递归节点
    tempPath.pop_back();	//遍历完所有的前驱节点,将当前结点v删除
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &st, &ed);    //n为顶点数,m为边数,s为起点
    int u, v;
    fill(G[0], G[0] + maxn * maxn, INF);
    fill(cost[0], cost[0] + maxn * maxn, INF);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d", &u, &v);
        scanf("%d%d", &G[u][v], &cost[u][v]);
        G[v][u] = G[u][v];
        cost[v][u] = cost[u][v];
    }
    Dijkstra(st);
    DFS(ed);
    for(int i = path.size() - 1; i >= 0; i--)
    {
        printf("%d ", path[i]);
    }
    printf("%d %d\n", d[ed], minCost);  //最短距离和花费
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值