题意:给出n个点,m条边,求去除任意一条边的最长最短路。
这题先用求一次最短路,记录下路径。如果去除的边不在路径上,那么最短路不变。所以我们只要考虑去除最短路上的边的情况。枚举最短路上的边删除,求最短路,注意要还原边。
这题用spfa的邻接矩阵形式怎么也过不了,一直TLE。代码不变,换成dijkstra之后就能过了。
ps:SPFA算法在负边权图上可以完全取代Bellman-ford算法,另外在稀疏图中也表现良好。但是在非负边权图中,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法,以及它的使用堆优化的版本。通常的SPFA算法在一类网格图中的表现不尽如人意。
dijkstra,floyd,bellman-ford,spfa算法比较:传送门
#include <iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#define N 1100
#define INF 0x7ffffff
using namespace std;
int d[N],pre[N],v[N],n,m,mp[N][N];
/*void spfa(int t)
{
for(int i=1;i<=n;i++) d[i]=INF,v[i]=0;
queue<int> q;
q.push(1);
v[1]=1;
d[1]=0;
while(!q.empty())
{
int c=q.front();
q.pop();
v[c]=0;
for(int i=1;i<=n;i++)
{
if(d[i]>d[c]+mp[c][i])
{
d[i]=d[c]+mp[c][i];
if(t) pre[i]=c;
if(!v[i]) v[i]=1,q.push(i);
}
}
}
}*///TLE
void dijkstra(int c)
{
for(int i=0;i<=n;i++) d[i]=INF,v[i]=0;
d[1]=0;
for(int i=1;i<=n;i++)
{
int t=-1,mmin=INF;
for(int j=1;j<=n;j++)
if(!v[j]&&mmin>d[j])
mmin=d[t=j];
if(t==-1) break;
v[t]=1;
for(int j=1;j<=n;j++)
if(d[j]>d[t]+mp[t][j])
{
d[j]=d[t]+mp[t][j];
if(c) pre[j]=t;
}
}
}//AC
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
mp[i][j]=INF;
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
mp[u][v]=mp[v][u]=w;
}
memset(pre,-1,sizeof(pre));
dijkstra(1);
int ans=d[n];
for(int i=n;i!=1;i=pre[i])
{
int t=mp[i][pre[i]];
mp[i][pre[i]]=mp[pre[i]][i]=INF;
dijkstra(0);
if(d[n]>ans) ans=d[n];
mp[i][pre[i]]=mp[pre[i]][i]=t;
}
cout<<ans<<endl;
}
}