题目地址:
https://www.acwing.com/problem/content/description/3559/
给定一个 n n n个点 m m m条边构成的无重边和自环的无向连通图。点的编号为 1 ∼ n 1∼n 1∼n。请问:从 1 1 1到 n n n的最短距离。去掉 k k k条边后,从 1 1 1到 n n n的最短距离。
输入格式:
第一行包含整数
T
T
T,表示共有
T
T
T组测试数据。
每组数据第一行包含三个整数
n
,
m
,
k
n,m,k
n,m,k。
接下来
m
m
m行,每行包含三个整数
x
,
y
,
z
x,y,z
x,y,z,表示点
x
x
x和点
y
y
y之间存在一条长度为
z
z
z的边。
最后一行包含
k
k
k个空格隔开的整数,表示去掉的边的编号。
所有边按输入顺序从
1
1
1到
m
m
m编号。
输出格式:
每组数据输出占两行。
第一行输出从
1
1
1到
n
n
n的最短距离。
第二行输出去掉
k
k
k条边后,从
1
1
1到
n
n
n的最短距离。无法到达,则输出
−
1
−1
−1。
数据范围:
1
≤
T
≤
10
1≤T≤10
1≤T≤10
1
≤
n
≤
50
1≤n≤50
1≤n≤50
1
≤
m
≤
n
(
n
−
1
)
2
1≤m≤\frac{n(n−1)}{2}
1≤m≤2n(n−1)
1
≤
x
,
y
≤
n
1≤x,y≤n
1≤x,y≤n
1
≤
z
≤
100
1≤z≤100
1≤z≤100
1
≤
k
≤
m
1≤k≤m
1≤k≤m
可以用Dijkstra算法。去掉 k k k条边的时候,直接标记一下那些边不能走即可。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 60, INF = 0x3f3f3f3f;
int n, m, k;
int g[N][N], dist[N];
bool vis[N];
int dijkstra() {
memset(dist, 0x3f, sizeof dist);
memset(vis, 0, sizeof vis);
dist[1] = 0;
for (int i = 0; i < n; i++) {
int t = -1;
for (int j = 1; j <= n; j++)
if (!vis[j] && (!~t || dist[t] > dist[j])) t = j;
if (t == n) return dist[t] == INF ? -1 : dist[t];
vis[t] = true;
for (int j = 1; j <= n; j++)
if (!vis[j] && ~g[t][j] && dist[j] > dist[t] + g[t][j])
dist[j] = dist[t] + g[t][j];
}
return -1;
}
int main() {
int T;
cin >> T;
while (T--) {
memset(g, -1, sizeof g);
scanf("%d%d%d", &n, &m, &k);
vector<pair<int, int>> es;
for (int i = 1; i <= m; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = c;
es.push_back({a, b});
}
printf("%d\n", dijkstra());
while (k--) {
int c;
scanf("%d", &c);
int x = es[c - 1].first, y = es[c - 1].second;
g[x][y] = g[y][x] = -1;
}
printf("%d\n", dijkstra());
}
}
每组数据时间复杂度 O ( n 2 ) O(n^2) O(n2),空间 O ( n ) O(n) O(n)。