P1186 玛丽卡 最短路spfa

  

题目描述

麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。

因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。

在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。

麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。

玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。

编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。

输入输出格式

输入格式:

第一行有两个用空格隔开的数NN和MM,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N \times (N-1)/21N1000,1MN×(N1)/2。城市用数字1-N1N标识,麦克在城市11中,玛丽卡在城市NN中。

接下来的MM行中每行包含三个用空格隔开的数A,B,VA,B,V。其中1≤A,B≤N,1≤V≤10001A,BN,1V1000。这些数字表示在AA和城市BB中间有一条双行道,并且在VV分钟内是就能通过。

输出格式:

一行,写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。

显然  先跑一下普通的最短路

然后对该最短路进行删除(因为删除别的不影响这条最短路) 枚举每条最短路边

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf=1e9+7;
inline int read()//拙劣的快读
{
    int p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
    return f*p;}
struct Edge
{
    int from,last,to,w;
}p[900009];//存边
int n,m,cnt,ans,head[900009],pre[900009],dis[1009],vis[1009];
int que[900009];//模拟队列 
bool f=1;//用来记录是否是第一次SPFA 
inline void add_edge(int x,int y,int W)//加边操作 
{
    cnt++;
    p[cnt].last=head[x];
    head[x]=cnt;
    p[cnt].from=x;//要记下每条边的起点 
    p[cnt].to=y;
    p[cnt].w=W;
}
inline void SPFA()//用来第一次SPFA(f)和最后删边后的SPFA(!f) 
{
    if(!f)memset(que,0,sizeof(que));//可以稍微快一点:第一次que和vis初始值均为0 
    memset(dis,inf,sizeof(dis));
    if(!f)memset(vis,0,sizeof(vis));
    int head_=0,tail_=1;
    vis[1]=1;
    dis[1]=0;
    que[tail_]=1;
    while(head_<=tail_)
         {
            int x=que[head_];
            head_++;vis[x]=0;
          for(int i=head[x];i;i=p[i].last)
              {
                  int t1=dis[x]+p[i].w;
                  if(dis[p[i].to]>t1)
                     {
                      dis[p[i].to]=t1;
                      if(f)pre[p[i].to]=i;
                      //第一次最短路:记录最短路上通向X点的边的邻接链表编号
                      if(!vis[p[i].to])
                         {
                          vis[p[i].to]=1;
                          que[++tail_]=p[i].to;
                               }
                        }
                 }
          }

}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
        {
            int x=read(),y=read(),w=read();
            add_edge(x,y,w);//双向边存两次 
            add_edge(y,x,w);
        }
    SPFA();//第一次全边跑一次SPFA 
    ans=dis[n];//记录第一次dis[n] 
    f=0;//开始删边标记 
    for(int i=pre[n];i;i=pre[p[i].from])//遍利所有边删边 
        {
            int old_value=p[i].w;
            p[i].w=inf;//枚举删除每一条边再次求最短路
            SPFA();
            p[i].w=old_value;//还原
            ans=max(ans,dis[n]);//统计符合题意的最大ans 
        }
    printf("%d",ans);
    return 0;
 }
View Code

猜你喜欢

转载自www.cnblogs.com/bxd123/p/10949444.html