次短路径问题

一、问题描述

P2865 [USACO06NOV] Roadblocks G

二、问题简析

如果求最短路径,我们很自然会想到 D i j k s t r a Dijkstra Dijkstra。但是,这道题要求的是次短路径。
记到 u u u 的最短路径为 d 1 [ u ] d_1[u] d1[u],到 u u u 的次短路径为 d 2 [ u ] d_2[u] d2[u]。则 d 2 [ v ] = d 1 [ u ] + e ( u , v ) d_2[v] = d_1[u] + e(u, v) d2[v]=d1[u]+e(u,v) or d 2 [ u ] + e ( u , v ) . w d_2[u] + e(u, v).w d2[u]+e(u,v).w
因此,我们需要求出所有顶点的最短路径和次短路径。我们依然可以采用 D i j k s t r a Dijkstra Dijkstra,只是多维护一个次短路径数组。

三、代码

#include <bits/stdc++.h>

using namespace std;

#define MAX 10				 // 最多顶点数
#define INF 1e8

typedef struct {int to, worth;} edge;

typedef pair<int, int> P;

int n, m;					// n -- 顶点数; m -- 边数
vector<edge> G[MAX];		// 邻接表
int d1[MAX], d2[MAX];		// d1 -- 最短路径; d2 -- 次短路径

struct cmp
{
	bool operator()(const P &a, const P &b)
	{
		return a.second > b.second;
	}
};

int quickin(void)
{
    int ret = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
        ch = getchar();
    while (ch >= '0' && ch <= '9')
    {
        ret = 10 * ret + ch - '0';
        ch = getchar();
    }
    return ret;
}

void solve(void)
{
	// 初始化
	fill(begin(d1), end(d1), INF);
	fill(begin(d2), end(d2), INF);
	d1[1] = 0;								  // 只能初始化d1[0],d2[0] > 0未知

	priority_queue<P, vector<P>, cmp> Q;	  // 最小优先队列
	Q.push(P(1, 0));
	while (!Q.empty())
	{
		P p = Q.top();
		Q.pop();
		int u = p.first;					  // p.second可能是最短路径也可能是次短路径

		if (d2[u] < p.second)    continue;	  // u的最短路径和次短路径都能进入下一步
		
		for (int i = 0; i < G[u].size(); i++)
		{
			edge e = G[u][i];
			int dis = p.second + e.worth;	  // 最短路径 or 次短路径 + e(u, v).w

			// 最短路径
			if (d1[e.to] > dis)
			{
				swap(d1[e.to], dis);		  // 交换后,dis >= d1[e.to]
				Q.push(P(e.to, d1[e.to]));	  // s 到 e.to 的最短路径
			}

			// 次短路径
			if (d2[e.to] > dis && d1[e.to] < dis)	// 次短路径必须大于最短路径
			{
				d2[e.to] = dis;
				Q.push(P(e.to, d2[e.to]));    // s 到 e.to 的次短路径
			}
		}
	}

	printf("%d\n", d2[n]);
}

int main()
{
	n = quickin(), m = quickin();
	for (int i = 0; i < m; i++)
	{
		int a, b, c;
		a = quickin(), b = quickin(), c = quickin();
		G[a].push_back(edge{b, c});
		G[b].push_back(edge{a, c});
	}

	solve();

	return 0;
}

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值