poj3255 Roadblocks (次短路)

题意:R条道路,N个路口,道路可以双向通过,问1路口到N路口的次短距离。同一条路可以走多次。

思路:Dijkstra算法。用一个二维数组dis[MAXN][2],去记录i->j的最短路径和次短路径,
dis[i][0]是表示当期拿记录最短边,dis[i][1]是表示当前记录次短边。使用book[maxn][2]来
标记最短/次短路,book[j][0]标记最短路,book[j][1]标记次短路。
dis初始值为0x3f3f3f,当if(!book[j][0]&&dis[j][0]<minn),即找到最短边,标记下来;   
如果 else if(!book[j][1]&&dis[j][1]<minn),则是次短边,标记下来。
后面是松弛操作,和dijk找最短路操作基本相似,如果if (minn==inf)成立,就是找不到次短路/最短路,break;
最后是dijk算法的更新操作,如果minn+w的距离小于dis[v][0]的距离,更新最短边,
如果minn+w的距离大于dis[v][0]但是小于dis[v][1]的距离,更新次短边。
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=5e4+10,inf=0x3f3f3f3f;
int head[maxn],cnt,dis[maxn][2];//0表示最短路径,1表示次短路径
int book[maxn][2];
int n,m;
struct node
{
	int w,v,nxt;
} pp[maxn*4];
void add(int u,int v,int w)//链式前进星自动排序
{
	pp[++cnt].v=v;
	pp[cnt].w=w;
	pp[cnt].nxt=head[u];
	head[u]=cnt;
}
void dijk(int x)
{
	int i,j;
	for (i=0; i<=n; i++)
	{
		book[i][0]=book[i][1]=0;
		dis[i][0]=dis[i][1]=inf;
	}
	dis[x][0]=0;

	for (i=1; i<n*2; i++)
	{
		int minn=inf,k=0,f=0;
		for (j=1; j<=n; j++)
		{
			if (!book[j][0]&&dis[j][0]<minn)//寻找最短路ing
			{
				minn=dis[j][0];
				k=j;
				f=0;
			}
			else if(!book[j][1]&&dis[j][1]<minn)//次短路
			{
				minn=dis[j][1];
				k=j;
				f=1;
			}
		}
		if (minn==inf)
			break;//没找到最短路或次短路  需要吗?

		book[k][f]=1;
		for (j=head[k]; j!=-1; j=pp[j].nxt)//
		{
			int w=pp[j].w,v=pp[j].v;
			if (dis[v][0]>=minn+w)//
			//目前边小于最短边,更新最短边,把最短边变成次短边
			{
				dis[v][1]=dis[v][0];
				dis[v][0]=minn+w;
			}
			else if (dis[v][1]>=minn+w)
				//目前边大于最短边,但小于次短边,则更新次短边
			{
				dis[v][1]=minn+w;
			}
		}
	}
}
int main()
{
	int i,j,x,y,z;
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	cnt=0;
	for (i=1; i<=m; i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	dijk(1);
	printf("%d\n",dis[n][1]);
	return 0;
}
posted @ 2021-01-31 20:09  索饮  阅读(68)  评论(0编辑  收藏  举报