最短路树在本题的应用可以大大降低时间复杂度。
题意求去掉一条边后所有点对的最短路径和c的最大值。
常规思路是枚举边,对于每一条删掉的边,我们都求出此时的c,然后比较。
但是这也意味着我们对于删掉的每条边都要做N次最短路,承受不起。
我们发现,如果删掉的边不在当前起点的最短路树上,这删掉的边不会影响该起点对答案的贡献。(每个起点对答案的贡献是以它为起点的最短路径之和)
所以我们只需要对于每一个起点,都求出它的最短路树,然后枚举边求解答案的时候判断一下该边在不在枚举起点的最短路树上即可。
如果在,说明要重新算。如果不在,直接用第一次dijk算出的答案即可。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 155, maxm = 2005, inf = 1e9; int n, m, l, tot; int h[maxn], w[maxn], dis[maxn], done[maxn], p[maxn][maxn], del[maxm]; struct edge { int v, next, w, id; }a[maxm]; struct edge2 { int u, v, w; }e[maxm]; struct node { int u, d; bool operator < (const node &rhs)const{ return d > rhs.d; } }; void add(int x, int y, int z, int id) { a[tot].id = id; a[tot].v = y; a[tot].w = z; a[tot].next = h[x]; h[x] = tot++; } priority_queue<node> q; void dijk(int s) { for (int i = 1; i <= n; i++) dis[i] = inf; memset(done, 0, sizeof done); dis[s] = 0; q.push((node){s, 0}); while (!q.empty()) { node x = q.top(); q.pop(); int u = x.u; if (done[u]) continue; done[u] = 1; for (int i = h[u]; ~i; i = a[i].next) { int v = a[i].v; if (dis[u] + a[i].w < dis[v]) { dis[v] = dis[u] + a[i].w; p[s][v] = u; q.push((node){v, dis[v]}); } } } for (int i = 1; i <= n; i++) if (dis[i] == inf) { w[s] += l; }else { w[s] += dis[i]; } } int dijk2(int s) { for (int i = 1; i <= n; i++) dis[i] = inf; memset(done, 0, sizeof done); dis[s] = 0; q.push((node){s, 0}); while (!q.empty()) { node x = q.top(); q.pop(); int u = x.u; if (done[u]) continue; done[u] = 1; for (int i = h[u]; ~i; i = a[i].next) { if (del[a[i].id]) continue; int v = a[i].v; if (dis[u] + a[i].w < dis[v]) { dis[v] = dis[u] + a[i].w; q.push((node){v, dis[v]}); } } } int t = 0; for (int i = 1; i <= n; i++) if (dis[i] == inf) t += l; else t += dis[i]; return t; } int main() { // freopen("uva4080.in","r",stdin); while (~scanf("%d%d%d", &n, &m, &l)) { memset(h, -1, sizeof h); tot = 0; for (int i = 1; i <= m; i++) { int x, y, z; scanf("%d%d%d", &x, &y, &z); e[i].u = x; e[i].v = y; e[i].w = z; add(x, y, z, i); add(y, x, z, i); } int ans1 = 0; for (int i = 1; i <= n; i++) { w[i] = 0; dijk(i); ans1 += w[i]; } printf("%d ", ans1); // for (int i = 1; i <= n; i++)//debug // { // printf("%d:%d ", i, w[i]); // } int ans = 0; for (int i = 1; i <= m; i++) { del[i] = 1; int u = e[i].u, v = e[i].v; int t = 0; for (int s = 1; s <= n; s++) { if(p[s][u] == v || p[s][v] == u)//在最短路树上 t += dijk2(s); else t += w[s]; } ans = max(ans, t); del[i] = 0; } printf("%d ", ans); } return 0; }