【图论】Dijkstra算法经典题目 之航线

航线–Dijkstra算法经典题目

图论除了最小生成树,Kruskal以外,Dijkstra算法也是重点的模块,Dijkstra算法变种题很多,经典的我也是收藏一下,以后方便寻找,hah

题目描述(废话,建议不看)

“呼!!终于到了,可是接下来要怎么走才能到达楚楚街港港呢?”亮亮在醋溜港直发愁。 突然“啾”的一下,一只银色小船出现在亮亮的面前,
上面坐着小精灵丹丹“又见面了,有什么可以帮助你的么?”小精灵向亮亮眨了眨眼睛,微笑着说。 “我想去楚楚街港,但我不知道要怎么走,
请问你可以告诉我么?”亮亮按捺着激动的	心	情轻声问道。 “楚楚街港呀......那是个特别美好的地方”小精灵歪着头想了想,说“我只能告诉
你大海上所有的航线,		  剩下的就只能靠你自己啦~” “只有所有的航
线呀”,亮亮的内心再三挣扎,却又没有其他的办法。 “不管有多困难,我一定要达到楚楚街港,请你告诉我吧”亮亮坚定地对小精灵说。
 小精灵欣赏地点了点头,递给亮亮一张航线图,并叮嘱道“时限是1000天,一定要到哦~”,然后如来时一般“啾”的一声,消失了。 亮亮现在
 迫切地想要抵达楚楚街  港,请问亮亮最快能在第几天抵达楚楚街港呢?

输入描述:

一行包含两个整数N(2<=N<=500),M(1<=M<=2000),用单个空格隔开。表示公有N个港,M条航线。起点为1,终点为N。
接下来M行,每行包含五个整数P,Q(1<=P,Q<=n), K(1<=K<=1000), X,Y(0<=X,Y<=10000),代表P,Q两个港有航线并需要K天,
并且该航线在第X天到第Y天天气恶劣	不可通行。

输出描述:

一个整数,即亮亮最快能在第几天抵达楚楚街港

输入

4 4      
2 1 1 7 13
4 3 2 10 11
1 3 8 9 12
2 3 3 2 10

输出

14

算法思想:

  1. 在这里用临界矩阵作为邻接表存储每一个节点的信息,由于信息很多,所以不考虑用pair<>而考虑用临界节点Node来存储所有的节点信息
  2. 若行船时间要与风暴时间有重合需要等到暴风雨结束才能出发

如果还不是很理解dijkstra算法的同学建议先点击:dijkstra算法模板详细介绍

这里的taken数组其实就是一个标记是否访问过,是否能作为下一次更新最短路径的bool型的st[]数组

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 500 + 5;
int dp[maxn], taken[maxn], n, m;
 
struct Node{
    int x, y, val, start, end;
    Node(int a, int b, int c, int d, int e){
        x = a; y = b; val = c; start = d; end = e;
    }
};
vector<Node> v[maxn]; //每一个起始点 对应的结构体, 作为拓扑图,这里是结构体Node作为拓扑图
 
int main(){
    while(scanf("%d%d", &n, &m) != EOF){
        memset(dp, 0x3f, sizeof(dp));  //初始化dp数组为0x3f,dp数组就是距离数组
        memset(taken, 0, sizeof(taken));
       
        for(int i = 0; i < m; i++){
            int a, b, c, d, e;
            scanf("%d%d%d%d%d", &a, &b, &c, &d, &e);
            Node n1(a, b, c, d, e); 
            Node n2(b, a, c, d, e); //这里jijkstra()算法算的是结构体
            v[a].push_back(n1); // v[a].push_back(n1); 从a出发到达的所有点的各种信息
            v[b].push_back(n2); // 双向边,反向建图
        }
        dp[1] = 0; //第一个点先经历 所以节点为1
        for(int k = 0; k < n; k++){
            int min_dp = -1; // min_dp是最小值,最小加进来的
            for(int i = 1; i <= n; i++)
                if(!taken[i] && (min_dp == -1 || dp[i] < dp[min_dp]))
                    min_dp = i;
            taken[min_dp] = 1;  //选择个最短的点 标记为已经加入最短距离的数组中,接下来用来哦更新其它点
            for(int i = 0; i < v[min_dp].size(); i++){
                Node n = v[min_dp][i]; //这一个点,也就是轩主最小距离min_dp的下一个点
                if(dp[n.x]>=n.end || (dp[n.x]+n.val)<n.start)//暴风雨来临前已经溜了或者暴风雨刮完了才到
                    dp[n.y] = min(dp[n.y], dp[n.x] + n.val);
                else dp[n.y] = min(dp[n.y], n.end + n.val);//要等暴风雨结束才能走
            }
        }
        cout<< dp[n] + 1<< endl;//天数是从第一天开始算的 没有第0天 所以加一
        
    }   
    return 0;
}

做个标记。挺经典的,图论之重点算法

你可能感兴趣的:(算法)