题意:给你一个无向图,要你求出任意两点的次短路。注意次短路一定要比最短路长。
思路:第一次做次短路的题。先求出任意两点间的最短路,dfs求次短路,如果当前次短路的长度<=已经走过的路的长度+接下来到终点的最短路 则返回。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 100 + 10;
const int maxe = 10000 + 10;
const int INF = 0x3f3f3f3f;
struct Edge{
int v, d;
int next;
Edge(int v = 0, int d = 0, int next = 0) : v(v), d(d), next(next) {}
};
int n, m;
int floyed[maxn][maxn];
int ans[maxn][maxn];
int Head[maxn], cntE;
Edge edge[maxe];
void init(){
memset(floyed, INF, sizeof(floyed));
memset(ans, INF, sizeof(ans));
memset(Head, -1, sizeof(Head));
for(int i = 0; i < n; i++) floyed[i][i] = 0;
cntE = 0;
}
void add(int u, int v, int d){
edge[cntE] = Edge(v, d, Head[u]);
Head[u] = cntE++;
edge[cntE] = Edge(u, d, Head[v]);
Head[v] = cntE++;
}
void Floyed(){
for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(floyed[i][k] != INF && floyed[k][j] != INF)
floyed[i][j] = min(floyed[i][j], floyed[i][k] + floyed[k][j]);
}
void dfs(int s, int t, int u, int cur_d){
if(ans[s][t] <= cur_d + floyed[u][t]) return;
if(cur_d + floyed[u][t] > floyed[s][t] && cur_d + floyed[u][t] < ans[s][t])
ans[s][t] = cur_d + floyed[u][t];
for(int i = Head[u]; ~i; i = edge[i].next){
int v = edge[i].v;
dfs(s, t, v, cur_d + edge[i].d);
}
}
int cas = 0;
void solve(){
init();
for(int i = 0; i < m; i++){
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
if(floyed[u][v] == INF) floyed[u][v] = floyed[v][u] = d;
else floyed[u][v] = floyed[v][u] = min(floyed[u][v], d);
add(u, v, d);
}
Floyed();
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(floyed[i][j] != INF)
dfs(i, j, i, 0);
int q;
printf("Set #%d\n", ++cas);
scanf("%d", &q);
while(q--){
int u, v;
scanf("%d%d", &u, &v);
if(ans[u][v] == INF) printf("?\n");
else printf("%d\n", ans[u][v]);
}
}
int main()
{
while(~scanf("%d%d", &n, &m)) solve();
return 0;
}