CF1433G 减少运费
1 CF1433G 减少运费
2 题目描述
时间限制 \(1s\) | 空间限制 \(256M\)
你是 \(Berlyatov\) 市的市长,市内总共有 \(n\) 个街区,他们由 \(m\) 条双向道路连接。第 \(i\) 条路连接街区 \(x_i\) 和 \(y_i\),运费是 \(w_i\)。每一对街区之间都有道路连接,所以整个城市是连通的。\(Berlyatov\) 市总共有 \(k\) 个运输道路,第 \(i\) 条道路从街区 \(a_i\) 到街区 \(b_i\)。每条路都有一个快递员,快递员总是选择最便宜的道路在街区 \(a_i\) 和 \(b_i\) 之间运输货物。有的道路是在街区内部连接,有些快递员的道路会重合(需要独立计算)。你最多只能走一条运费为 \(0\) 的道路。假设 \(d(x,y)\) 是在街区 \(x\) 和 \(y\) 之间最便宜的运费。你的任务是如果可以选择一些道路把它的运费改为 \(0\),找出可能的最低总路线成本。换句话说,经过上面优化后找出最小的 \(\sum_{i=1}^{k}{d(a_i,b_i)}\)。
数据范围:\(2≤𝑛≤1000; 𝑛−1≤𝑚≤𝑚𝑖𝑛(1000,\frac{𝑛(𝑛−1)}{2});1≤𝑘≤1000\)。
3 题解
分类讨论可以发现:在改变了某条边的边权后,可能使某些之前包括该边的最短路长度减小了,也有可能对答案毫无影响,也有可能让一些最短路改变了路径。对于第一种和第三种情况,我们可以取以下两种情况的最小值:
\(1.\) 起点到 \(u\) 的最短路长度加上 \(v\) 到终点的最短路长度。
\(2.\) 起点到 \(v\) 的最短路长度加上 \(u\) 到终点的最短路长度。
这两种情况包括了在最短路经过 \(u \to v\) 这条边时答案的所有可能值,而我们只需要将这两个值与起点到终点到最短路长度作比较,取其中的最小值即可。我们这里可以预处理出以每个点为源点的全图单源最短路,以便后面使用。这样,总时间复杂度就是 \(O(n^2\log_2 m + mk)\),可以稳定过 \(10^3\)。
代码(空格警告):
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e3+10;
int n, m, k, tot, u, v, w, ans, minn;
int head[N], ver[N*2], last[N*2], edge[N*2];
int dist[N][N], a[N], b[N], U[N], V[N];
bool f[N];
priority_queue< pair<int, int> > q;
void add(int x, int y, int z)
{
ver[++tot] = y;
last[tot] = head[x];
edge[tot] = z;
head[x] = tot;
}
void dij(int s)
{
for (int i = 0; i <= 1e3+9; i++) dist[s][i] = 0x3f3f3f3f;
memset(f, 0, sizeof(f));
dist[s][s] = 0;
q.push(make_pair(0, s));
while (q.size())
{
int x = q.top().second; q.pop();
if (f[x]) continue;
f[x] = 1;
for (int i = head[x]; i; i = last[i])
{
int y = ver[i], z = edge[i];
if (dist[s][x] + z < dist[s][y])
{
dist[s][y] = dist[s][x] + z;
q.push(make_pair(-dist[s][y], y));
}
}
}
}
int main()
{
cin >> n >> m >> k;
for (int i = 1; i <= m; i++)
{
cin >> u >> v >> w;
U[i] = u;
V[i] = v;
add(u, v, w);
add(v, u, w);
}
for (int i = 1; i <= n; i++) dij(i);
for (int i = 1; i <= k; i++) cin >> a[i] >> b[i];
minn = 0x3f3f3f3f;
for (int i = 1; i <= m; i++)
{
ans = 0;
for (int j = 1; j <= k; j++)
{
ans += min(dist[a[j]][b[j]], min(dist[a[j]][U[i]] + dist[b[j]][V[i]], dist[a[j]][V[i]] + dist[b[j]][U[i]]));
}
minn = min(ans, minn);
}
cout << minn;
return 0;
}