转载请注明本文地址
这题跟这题的题意是一样的,但是也有两点区别:1.1号点到n号点可以不连通 2.有重边。其中第二点可以导致题目变得更麻烦一点。
思路:
用邻接表写会简单一些,但是我还是用临界矩阵写了。
1.整体思路跟上面给的那个链接的做法是一样的,也是枚举最短路上的边(正面见那个链接),然后删除,跑最短路,取最长的那个。
2.考虑到每次只删一条边,那么即使有重边,那实际有效的也只是每条边重边中的最短和次短的边,因此在保存邻接矩阵的时候,邻接矩阵仍然存最小的边,而另外开数组second[]来记录次短的边。然后删边的时候只要把次短的(即使是inf)赋到邻接矩阵里就可以了,删完之后要记得恢复。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> using namespace std; const int MAXV=1100; const int inf=0x3f3f3f3f; int n,m; int map[MAXV][MAXV],second[MAXV][MAXV]; int d[MAXV],pre_1[MAXV],pre_2[MAXV]; bool inq[MAXV]; void init() { fill(map[0],map[0]+MAXV*MAXV,inf); fill(second[0],second[0]+MAXV*MAXV,inf); memset(pre_1,-1,sizeof(pre_1)); memset(pre_2,-1,sizeof(pre_2)); memset(inq,0,sizeof(inq)); } void SPFA(int s,int pre[]) { deque<int> Q; Q.push_front(s); fill(d,d+MAXV,inf); d[s]=0; while(!Q.empty()) { int u=Q.front(); Q.pop_front(); inq[u]=false; for(int v=0;v<n;v++) { if(map[u][v]!=inf && d[v]>d[u]+map[u][v]) { d[v]=d[u]+map[u][v]; pre[v]=u; if(!inq[v]) { inq[v]=true; if(!Q.empty() && d[v]<=d[Q.front()]) Q.push_front(v); else Q.push_back(v); } } } } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(); int u,v,dis; for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&dis); u--,v--; if(dis<map[u][v]) second[u][v]=second[v][u]=map[u][v],map[u][v]=map[v][u]=dis; else if(dis<second[u][v]) second[u][v]=second[v][u]=dis; } SPFA(0,pre_1); v=n-1; int ans=d[n-1],temp; while(v!=0) { u=pre_1[v]; temp=map[u][v]; map[u][v]=map[v][u]=second[u][v]; SPFA(0,pre_2); ans=max(ans,d[n-1]); if(ans==inf) break; map[u][v]=map[v][u]=temp; v=u; } if(ans==inf) printf("-1\n"); else printf("%d\n",ans); } return 0; }