洛谷 P2865 [USACO06NOV]路障Roadblocks

题目

题意:求无向图中起点到终点的次短路。

思路:用两次dijkstra,分别正向和反向遍历一边,求出到起点的最短路dis1[]和到终点的最短路dis2[],然后再枚举每一条边 $ u->v $ ,令
$ d = dis1[u] + dis2[y] + edge.w $ ,在满足 $ d<dis1[n] $ 的条件下求出最小的d即为次短路的长度。

Code:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
//Mystery_Sky
//
#define M 1000100
struct Edge{
	int to, w, next;
}edge[M];
int n, m;
int head[M], cnt, dis1[M], dis2[M], vis[M];
inline void add_edge(int u, int v, int w) {edge[++cnt].to = v; edge[cnt].w = w; edge[cnt].next = head[u]; head[u] = cnt;}
struct node{
	int dis;
	int pos;
	inline bool operator <(const node &x)const{
		return x.dis < dis;
	}
};
priority_queue <node> Q;
inline void dijkstra()
{
	dis1[1] = 0;
	Q.push((node){0, 1});
	while(!Q.empty()) {
		node top = Q.top(); Q.pop();
		int x = top.pos;
		if(vis[x]) continue;
		vis[x] = 1;
		for(int i = head[x]; i; i = edge[i].next) {
			int y = edge[i].to;
			if(dis1[y] > dis1[x] + edge[i].w) {
				dis1[y] = dis1[x] + edge[i].w;
				if(!vis[y]) Q.push((node){dis1[y], y}); 
			}
		}
	} 
}

inline void dijkstra_1()
{
	memset(vis, 0, sizeof(vis));
	dis2[n] = 0;
	Q.push((node){0, n});
	while(!Q.empty()) {
		node top = Q.top(); Q.pop();
		int x = top.pos;
		if(vis[x]) continue;
		vis[x] = 1;
		for(int i = head[x]; i; i = edge[i].next) {
			int y = edge[i].to;
			if(dis2[y] > dis2[x] + edge[i].w) {
				dis2[y] = dis2[x] + edge[i].w;
				if(!vis[y]) Q.push((node){dis2[y], y}); 
			}
		}
	} 
}
int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= m; i++) {
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		add_edge(u, v, w); add_edge(v, u, w);
	}
	for(int i = 1; i <= n; i++) dis1[i] = dis2[i] = 0x3f3f3f3f;
	dijkstra();
	dijkstra_1();
	int ans = 0x3f3f3f3f;
	for(int i = 1; i <= n; i++) {
		for(int j = head[i]; j; j = edge[j].next) {
			int y = edge[j].to;
			int d = dis1[i] + dis2[y] + edge[j].w;
			if(d < ans && d > dis1[n]) ans = d;
		}
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2019-11-12 18:10  Mystery_Sky  阅读(171)  评论(0编辑  收藏  举报