[洛谷]P2865 [USACO06NOV]路障Roadblocks

题目描述

贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。 贝茜所在的乡村有R(1<=R<=100,000)条双向道路,每条路都联结了所有的N(1<=N<=5000)个农场中的某两个。贝茜居住在农场1,她的朋友们居住在农场N(即贝茜每次旅行的目的地)。 贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。

题目解析

一个裸的次短路,很简单。
求出起点和终点的单源最短路。
枚举每一条边,表示必经过这条边的最短路,若这条路径大于原最短路,则可能为次短路,取个 M i n Min Min值即可

代码

#include
#define N 5005
#define ll long long
using namespace std;
int n,r,ans=1e9;
int dis[2][N],ax[N*40],ay[N*40],aw[N*40];
queue<int> q;
bool vis[N];

int ls[N],cnt;
struct node
{
	int v,next,w;
}a[N*40];
void add(int x,int y,int w)
{
	a[++cnt].v=y;a[cnt].w=w;a[cnt].next=ls[x];ls[x]=cnt;
}

void spfa(int s)
{
	int x=0;
	if(s==n) x=1;
	dis[x][s]=0;
	q.push(s);
	while(!q.empty())
	{
	  int u=q.front();q.pop();
	  vis[u]=0;
	  for(int i=ls[u];i;i=a[i].next)
	  {
	  	int v=a[i].v;
	  	if(dis[x][u]+a[i].w<dis[x][v])
	  	{
	  	  dis[x][v]=dis[x][u]+a[i].w;
	  	  if(!vis[v])
	  	   vis[v]=1,q.push(v);
		}
	  }
	}
}

int main()
{
	freopen("block.in","r",stdin);
	freopen("block.out","w",stdout);
	cin>>n>>r;
	for(int i=1,x,y,w;i<=r;i++)
	{
	  cin>>x>>y>>w;
	  ax[i]=x;ay[i]=y;aw[i]=w;
	  add(x,y,w);add(y,x,w);
	}
	memset(dis,0x3f,sizeof(dis));
	spfa(1);spfa(n);
	for(int i=1;i<=r;i++)
	{
	  int xx=dis[0][ax[i]]+aw[i]+dis[1][ay[i]],yy=dis[0][ay[i]]+aw[i]+dis[1][ax[i]];
	  if(xx!=dis[0][n]) ans=min(ans,xx);
	  if(yy!=dis[0][n]) ans=min(ans,yy);
	}
	cout<<ans;
	return 0; 
}

你可能感兴趣的:([洛谷]P2865 [USACO06NOV]路障Roadblocks)