【POJ3255/洛谷2865】[Usaco2006 Nov]路障Roadblocks(次短路)

题目:

POJ3255

洛谷2865

分析:

这道题第一眼看上去有点懵……

不过既然要求次短路,那估计跟最短路有点关系,所以就拿着优先队列优化的Dijkstra乱搞,搞着搞着就通了。

开两个数组:(dis)存最短路,(dis2)存次短路

在松弛的时候同时更新两个数组,要判断三个条件

(u)是当前考虑的点,(v)是与(u)有边相连的点,(d(u,v))表示从(u)(v)的边长)

1.如果(dis[v]>dis[u]+d(u,v)),则更新(dis[v])

2018.11.09Updated: 同时(dis2[v])应成为原(dis[v])。原代码有误,已更新。

2.如果(dis[v]<dis[u]+d(u,v))(不能取等,否则(dis2[v])(dis[v])可能相等)且(dis2[v]>dis[u]+d(u,v)),则更新(dis2[v])

3.如果(dis2[v]>dis2[u]+d(u,v)),则更新(dis2[v])(显然,如果2成立,更新后(dis2[v]=dis[u]+d(u,v)<dis2[u]+d(u,v)),即3一定不成立)

如果上述三个条件中有任意一个成立,则将(v)入队。

还要注意一个地方:因为次短路可能会走“回头路” (即成环) ,所以一个点可以多次进队,不能使用(vis)数组判重。

以及起点的(dis2)不能初始化为0,因为起点的次短路一定是沿着与其相连的最短的边走出去再回来。

代码:

#include<cstdio>
#include<algorithm>
#include<queue> 
#include<cstring>
#include<vector>
using namespace std;
int dis[5010],dis2[5010],n,m;
struct point
{
	int id;
	int dis;
	bool operator<(const point &b)const
	{
		return dis>b.dis;
	}
};
struct edge
{
	int to;
	int w;
};
priority_queue<point>q;
vector<edge>g[5010];
int main(void)
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		g[a].push_back((edge){b,c});
		g[b].push_back((edge){a,c});
	}
	memset(dis,0x3f3f3f3f,sizeof(dis));
	memset(dis2,0x3f3f3f3f,sizeof(dis2));
	dis[1]=0;
	q.push((point){1,0});
	while(!q.empty())
	{
		int u=q.top().id,d=q.top().dis;
		q.pop();
		if(d>dis2[u])continue;
		for(int i=0;i<g[u].size();i++)
		{
			int v=g[u][i].to,w=g[u][i].w;
			bool flag=false;
			if(dis[v]>dis[u]+w)
			{
				dis2[v]=dis[v];
				dis[v]=dis[u]+w;flag=true;
			}
			if(dis[v]<dis[u]+w&&dis2[v]>dis[u]+w)
				dis2[v]=dis[u]+w,flag=true;
			
			if(dis2[v]>dis2[u]+w)
				dis2[v]=dis2[u]+w,flag=true;
				
			if(flag)q.push((point){v,dis[v]});
		}
	}
	printf("%d",dis2[n]);
	return 0;
}
原文地址:https://www.cnblogs.com/zyt1253679098/p/8867678.html