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;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-31 15:26  David24  阅读(52)  评论(0编辑  收藏  举报