NKOJ P1107 ---- 达喀尔拉力赛

问题描述

何老板在今年的达喀尔汽车拉力赛中表现出色。现在还剩下最后一站的比赛,地图上总共有n(不超过500)个城市,最后一站的起点是1号城市,终点是n号城市。这些城市间有m(不超过10000)条道路相连接。何老板估计:因为是最后一站,所以选手们一定会选最近的道路行驶,所以这些道路上一定非常容易堵车。所以何老板决定选从起点到终点的第二短的道路行驶。问:第二短的道路是多长?

何老板选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。        

输入格式

        第1行: 两个整数,n和m,用空格隔开
        第2..m+1行: 每行包含三个用空格隔开的整数A、B和D,表示存在一条长度为D(1 <= D <= 5000)的路连接城市A和城市B

输出格式

        1行: 输出一个整数,即城市1到城市N的第二短路的长度

样例输入

        4 44
        1 2 100
        2 4 200
        2 3 250
        3 4 100

样例输出

        450

友情提示: 该文章有多处“透明字”,请不要忽略任何一处“空白”

                                                                                                                                        何老板yyds

-----------------------------------------------------------------------------------------------------------   华丽的分割线~

# 1.思路

        次短路问题

                最短路问题

                       


如果你连最短路都不会,请先搞懂Floyd,DIjkstra( + 已死的SPFA)

如果你连图(论)是啥都不知道,请先了解图(论)

友情链接:图论Dijkstra


# 2.怎么写?

        这里推荐Dijkstra,也只讲Dijkstra

        Dijkstra求次短路

        首先我们要开好数组

        你需要结构体数组以链是向前星的存储(这种方式比二维数组好一些,数据大了二维数组还会爆)

        一个ls数组,dis数组要开两个或者开二维,vis数组也要开二维

int ls[maxn];
long long dis[maxn][2];
bool vis[maxn][2];
//建议dis数组开long long

        然后是输入,记住此题是无向边,要存两个方向的

        

        Dijkstra函数部分

        #伪代码

        Dijkstra(s, e) {

                int k,t,y,z,min;

                初始化,初始化两维

dis[i][0] = dis[i][1] = inf;
vis[i][0] = vis[i][1] = 0;

                dis[s][0]

                do-while{ // 在此神奇地发现:不能用do-while,不知道为什么        因为我是蒟蒻                                            // 后来查了查,有,这种写法,大家可以参考参考

                        for (int i = 1; i <= n; i++) {

                                if (dis[i][0] < min && !vis[i][0]) {

                                        ……

                                        t = 0

                                } else if (dis[i][1] < min && !vis[i][1]) {

                                        ……

                                        t = 1

                                } //ps: if-else 语句中要加一个变量,看min是次短的还是最短的

                        }

                        if (k) {
                                v数组标记

                                while (j != 0) {

                                        y = Map[j].y, z = Map[j].z;

                                        如果min + z < dis[y][0] : dis[y][1] = dis[y][0]; dis[y][0] = min + z;

                                                // 此时 最短路有最小的了,那么刚才的最短路就变成了次短路

                                        否则 min + z > dis[y][0] 但 小于dis[y][1] :更新次短

                                         j = Map[j].next;记得补一句

                                } // 等效于 (for (int j = last_side[u]; j; j = Map_of_side[j].next))

                        }

                }

        }

        printf(dis[e][1]);

3.核心代码

        你们滴缀爱(我能说我也爱吗?不能)

#核心代码
int k, t, y, z, min;
	for (int i = 1; i <= n; i++) {
		dis[i][0] = dis[i][1] = inf;
		vis[i][0] = vis[i][1] = 0;
	}
	dis[s][0] = 0;
	do {
		k = 0;
		min = inf;
		for (int i = 1; i <= n; i++) {
			if (dis[i][0] < min && !vis[i][0]) {
				min = dis[i][0];
				k = i;
				t = 0;
			} else if (dis[i][1] < min && !vis[i][1]) {
				min = dis[i][1];
				k = i;
				t = 1;
			}
		}
		if (k > 0) {
			vis[k][t] = 1;
			int j = ls[k];
			while (j != 0) {
				y = Map[j].y, z = Map[j].z;
				if (min + z < dis[y][0]) {
					dis[y][1] = dis[y][0];
					dis[y][0] = min + z;
				} else if ((min + z < dis[y][1]) && (min + z > dis[y][0])) {
					dis[y][1] = min + z;
				}
				j = Map[j].next;
			}
		}
	}while(k > 0);

想要完整代码

行吧

啊哈哈哈哈哈哈!!被坑了吧

都给到这个份上了

没门!


THE END


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值