题意:
给定一张图,从1到n,若能随便去除一条路,问重 1 到 n 最短路?
得:
1 通过本题,知道了如何对重边进行处理 。给每一条边设置一个id,这样可以把 a到b间的重边区分开。当重边的某一个条边被使用时,将它的id标记出来,以后就可以通过判断id是否被标记过来判断使用过的是重边中的那一条边。
2 把生成树中的点标记出来,
for(int i = 0; i < N; i++)
pre[i] = -1; //初始化根节点。
pre[v] = u; //标记每个点的根。
遍历生成树中的个点;
for(int i = n; i != -1; i = pre[i])
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;
const int inf = 0x7fffffff;
const int M = 1005;
struct node {
int v;
int id;
int time;
};
int path[M];
int dist[M];
int vist[M];
int q[M*60];
int edge[M*60];
vector<node>road[M*M/2];
int n, m, ans1;
int ans, sum;
node cur;
bool flag;
void init(){
ans = inf;
for(int i = 0; i <= n;i++){
path[i] = -1;
road[i].clear();
}
}
void spfa(){
queue<int>que;
memset(edge, 0, sizeof(edge));
for(int i = 1; i <= n; i++){
dist[i] = inf;
vist[i] = 0;
}
dist[1] = 0;
que.push(1);
vist[1] = 1;
while(!que.empty()){
int u = que.front();
vist[u] = 0;
que.pop();
for(int i = 0; i < (int)road[u].size(); i++){
cur = road[u][i];
int v = cur.v;
int time = cur.time;
if(dist[v] > dist[u] + time){
dist[v] = dist[u] + time;
path[v] = u; //记录最小生成树的点,极其根节点。
q[v] = cur.id; //记录最小生成树上的对应的边。为后面的替换做准备。
if(!vist[v]){
que.push(v);
vist[v] = 1;
}
}
}
}
//printf("ans = %d\n", dist[n]);
}
int spfa2() {
queue<int>que;
for(int i = 1; i <= n; i++){
dist[i] = inf;
vist[i] = 0;
}
dist[1] = 0;
vist[1] = 1;
que.push(1);
while(!que.empty()){
int u = que.front();
vist[u] = 0;
que.pop();
for(int i = 0; i < (int)road[u].size(); i++){
cur = road[u][i];
int v = cur.v;
int time = cur.time;
if(edge[cur.id]) //不让本次操作要替换的点,进入队列。
continue;
if(dist[v] > dist[u] + time){
dist[v] = dist[u] + time;
if(!vist[v]){
que.push(v);
vist[v] = 1;
}
}
}
}
return dist[n];
}
int main()
{
int t;
int x, y, time;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
init();
for(int i = 0; i < m; i++){
scanf("%d%d%d", &x, &y, &time);
cur.v = x;
cur.id = i; //这里用不同边有不同的id号,分别重边问题。(很好的方法)
cur.time = time;
road[y].push_back(cur);
cur.v = y;
road[x].push_back(cur);
}
spfa();
if(dist[n] == inf){
printf("-1\n");
continue;
}
bool sign = true;
for(int i = n; path[i] != -1; i = path[i]){ //遍历所有最小生成树的点。
edge[q[i]] = 1; //把最小生成树上的该边替换。做法是不让其参与松弛操作。
sum = spfa2();
edge[q[i]] = 0; //把该边解标记。
if(sum == inf)
break;
if(sign){ //替换的一条边,得到的最小生成树。
ans = sum;
sign = false;
}else
ans = max(ans, sum);
}
if(ans == inf)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}