>Description
共有N个街区和M条道路,每条道路连接两个不同的街区,并且通过一条道路需要花费一些时间。从1号街区赶往N号街区,并且你要选择一条道路不能通行,不过不论是哪条道路不能通行,均存在一条路径可以从1号街区前往N号街区,而且亚丝娜一定会选取最短路前往N号街区。亚丝娜最多要花费多长的时间才能到达N号街区。
>Input
第1行:两个正整数N,M,N表示街区个数,M表示道路数。
第2到M+1行 每行三个整数 u,v,w 表示存在一条连接u和v的道路,通过这条道路花费的时间为w
数据保证没有重边和自环
>Output
一个整数,表示最多花费的时间。
>Sample Input
5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10
>Sample Output
27
【数据规模】
30% N<=5, M<=10
60% N<=1000,M<=10000,w=1
100% N<=1000, M<=N*(N-1)/2,1<=w<=1000
>解题思路
首先要用SPFA算出从1到n的最短路,并且要记录路径。
然后再枚举这条路径上的各个点不能通行的情况(因为如果是除最短路径外的其他的不能通行的话,亚丝娜肯定会走最短路径,所以只用枚举最短路径上的点),算出最长时间。
>代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct ooo
{
int to,next;
}a[1000005];
int n,m,u,v,w,h[1005],t,f[1005][1005],st[3005],head,tail,lhq[1005],c[1005],tt,ans;
bool yy[1005];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
a[++t].to=v; a[t].next=h[u]; h[u]=t;
a[++t].to=u; a[t].next=h[v]; h[v]=t;
f[u][v]=f[v][u]=w;
}
memset(c,0x7f,sizeof(c));
c[1]=0; st[1]=1; yy[1]=1; head=0; tail=1;
do
{
head++;
for(int i=h[st[head]];i;i=a[i].next)
if(c[st[head]]+f[st[head]][a[i].to]<c[a[i].to])
{
lhq[a[i].to]=st[head]; //记录最短路径:表示当前点从哪个点过来
c[a[i].to]=c[st[head]]+f[st[head]][a[i].to];
if(!yy[a[i].to])
{
st[++tail]=a[i].to;
yy[a[i].to]=1;
}
}
yy[st[head]]=0;
}while(head<tail);
ans=c[n]; tt=n;
for(int k=lhq[n];k;k=lhq[k]) //枚举每个点
{
memset(c,0x7f,sizeof(c)); //每次都要处理
c[1]=0; st[1]=1; yy[1]=1; head=0; tail=1;
do
{
head++;
for(int i=h[st[head]];i;i=a[i].next)
if(st[head]!=k||a[i].to!=tt) //特判:这条路不能通行
if(c[st[head]]+f[st[head]][a[i].to]<c[a[i].to])
{
c[a[i].to]=c[st[head]]+f[st[head]][a[i].to];
if(!yy[a[i].to])
{
st[++tail]=a[i].to;
yy[a[i].to]=1;
}
}
yy[st[head]]=0;
}while(head<tail); //算出最短路径
tt=k;
if(c[n]!=c[0]) ans=max(ans,c[n]);
}
printf("%d",ans);
return 0;
}