单源次短路

305 阅读1分钟

算法思想

记d[v]为节点1到v的最短路,d_[v]为次短路,对于一条u->v的边,d_[v]要么是d_[u]加边权要么是d[u]加边权。即

d_[v]=min(d_[u]+w,d[u]+w)d\_[v]=min(d\_[u]+w,d[u]+w)

设若1->v只有一条路,d_[v]=INF。
和Dijkstra算法类似,每次先判断经过u的这条路径是否可以更新最短路,如果不能更新,就看能否更新次短路,如果可以更新,就用之前的最短路更新次短路。由于每次都要用到节点u的次短路的信息,所以每次都要push节点的次短路。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=5001,M=1E5+1,INF=0x3f3f3f3f;
int n,r,tot;
int d[N],d_[N],head[N],vis[N];
struct Node{
	int p,dis;
	bool operator < (const Node &tmp) const
	{
		return dis>tmp.dis;
	}
};
struct Edge{
	int to,val,nxt;
}e[2*M];
priority_queue<Node> q;
inline void add_edge(int u,int v,int w,int flag)
{
	e[++tot].nxt=head[u];e[tot].to=v;e[tot].val=w;head[u]=tot;
	if(flag)
		add_edge(v,u,w,0);
}
inline int read()
{
	int ret=0;char ch=getchar();
	while(ch<'0' || ch>'9') 
		ch=getchar();
	while(ch>='0' && ch<='9')
	{
		ret=ret*10+ch-'0';
		ch=getchar();
	}
	return ret;
}
void S_Dijkstra()
{
	rep(i,1,n)
	{
		d[i]=INF;
		d_[i]=INF;
	}
	d[1]=0;
	Node fir={1,0};
	q.push(fir);
	while(!q.empty())
	{
		Node cur=q.top();q.pop();
		int u=cur.p;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to,dis=cur.dis+e[i].val;
			if(d_[v]<dis)
				continue;
			if(d[v]>dis)
			{
				swap(dis,d[v]);
				Node tmp={v,d[v]};
				q.push(tmp);
			}
			if(d_[v]>dis && d[v]<dis)
			{
				d_[v]=dis;
				Node tmp={v,d_[v]};
				q.push(tmp);
			}
		}
	}
}
int main()
{
	// freopen("in.in","r",stdin);
	n=read();r=read();
	int u,v,w;
	rep(i,1,r)
	{
		u=read();v=read();w=read();
		add_edge(u,v,w,1);
	}
	S_Dijkstra();
	cout<<d_[n]<<endl;