洛谷1186 玛丽卡

玛丽卡

题目描述:
      麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。
      因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。
      在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。
      麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。
      玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。
编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。


输入格式:
      第一行有两个用空格隔开的数N和M,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N*(N-1)/2。城市用数字1至N标识,麦克在城市1中,玛丽卡在城市N中。
接下来的M行中每行包含三个用空格隔开的数A,B和V。其中1≤A,B≤N,1≤V≤1000。这些数字表示在A和城市B中间有一条双行道,并且在V分钟内是就能通过。


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

输入样例#1:
5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10

输出样例#1:
27

解析:
      题意其实就是从一个点到另一个点在其中一条路径被破坏的情况下能够到达的最短路径的最大值。
      那么我们可以先算出最短路径,然后会出现以下两种情况:
      1.破坏的路径不在最短路径上:对路径长度无影响。
      2.破坏的路径在最短路径上:对路径长度有影响。
      综上,我们就可以破坏掉最短路径上的每一条边,跑一遍dijkstra,取最大值,即为答案。
      当然,如果最短路径有多条且有重复部分或者不重复,那么只有重复部分的边对答案有影响或者没有影响,所以这个算法仍然是正确的。

代码:
#include <bits/stdc++.h>
using namespace std;

const int Max=1001000;
int n,m,s=-1,tot;
int p[Max];
int size[Max];
int first[Max],dis[Max];
struct shu{int to,next,len;};
shu bian[Max*4];
inline int get_int()
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();}
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}

inline void build(int x,int y,int z)
{
   s++;
   bian[s].next=first[x];
   first[x]=s;
   bian[s].to=y;
   bian[s].len=z;
}

inline void dijkstra()
{
   priority_queue<pair<int,int> >q;
   memset(dis,127,sizeof(dis));
   dis[n]=0;
   q.push(make_pair(0,n));
   while(!q.empty())
   {
   	 int point=q.top().second;
   	 if(point==1) return;
   	 q.pop();
     for(int u=first[point];u!=-1;u=bian[u].next)
     {
       if(dis[point]+bian[u].len<dis[bian[u].to])
       {
         dis[bian[u].to]=dis[point]+bian[u].len;
         q.push(make_pair(-dis[bian[u].to],bian[u].to));
       }
     }
   }
}

inline void dfs(int point)    //求出最短的路径
{
   if(point==n) return;
   for(int u=first[point];u!=-1;u=bian[u].next)
   {
   	 if(dis[bian[u].to]==dis[point]-bian[u].len)
   	 {
   	   size[++tot]=u;
       dfs(bian[u].to);
       return;
   	 }
   }
}

int main()
{
   //freopen("lx.in","r",stdin);
   //freopen("lx.out","w",stdout);
   memset(first,-1,sizeof(first));

   n=get_int();
   m=get_int();
   for(int i=1;i<=m;i++)
   {
   	 int x=get_int(),y=get_int(),z=get_int();
     build(x,y,z);
     build(y,x,z);
   }

   dijkstra(); 

   dfs(1);

   int ans=0;
   for(int i=1;i<=tot;i++)
   {
   	   int x=bian[size[i]].len;
   	   bian[size[i]].len=1e9;     //将破坏的边赋成极大值
   	   bian[(size[i])^1].len=1e9;
   	   dijkstra();
   	   ans=max(ans,dis[1]);
   	   bian[size[i]].len=x;      //注意计算后要恢复
   	   bian[(size[i])^1].len=x;
   }

   cout<<ans<<endl;
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值