AcWing 340. 通信线路

发布时间 2023-07-10 12:31:22作者: is_land

题目传送门:340. 通信线路 - AcWing题库

 

题目大致意思

对于一条路径,他的花费是,其经过的所以路线中花费最大的一条,你可以选择k条线,使其变为免费,求1到n的最小花费。

 

解题方法

本题可以用spfa加上dp来写。

对于同样是单源最短路,不可以用dijkstra的原因是:该题会将路径更改为0,如果用dijstra是不能更新已经确定的点,所以不可以使用。

为了做到更新点,我们使用队列优化的spfa。

我们知道普通的spfa是对于每一个点,扫描一边所以的边,但是队列优化的spfa是当影响该边的上一条边被更新,然后才更新该边,这样就不用扫描所有的边。

根据题意,我们可以用dp来表示费用,dp[x][p]表示从1~x,我们使用了p次免费的花费。如果有一条边x到y,花费为z加入,那么dp[y][p] = max(dp[x][p], z)。

接下来就是dp的公式,对于一条边,我们可以选择原价买下和让其免费。

那么我们可以得到dp[y][p] = min(dp[x][p - 1], max(dp[x][p], z))。其中dp[x][p-1]表示使用免费,max(dp[x][p], z)表示不使用免费。

AC代码:

#include <bits/stdc++.h>
using namespace std;

int ne[10010 * 2], e[10010 * 2], w[10010 * 2], h[1010], idx;
int dp[1010][1010];
int sta[1010];
int n, p, k;

void add(int x, int y, int z) // 邻接表建图
{
    e[idx] = y;
    w[idx] = z;
    ne[idx] = h[x];
    h[x] = idx++;
}

void spfa()
{
    queue<int> q;
    q.push(1);
    dp[1][0] = 0;
    sta[1] = 1;

    while (!q.empty())
    {
        int x = q.front();
        q.pop();
        sta[x] = 0;

        for (int i = h[x]; i != -1; i = ne[i])
        {
            int y = e[i], z = max(dp[x][0], w[i]); // 对于p = 0时
            if (dp[y][0] > z)
            {
                dp[y][0] = z;
                if (sta[y] == 0)
                {
                    sta[y] = 1;
                    q.push(y);
                }
            }

            for (int p = 1; p <= k; p++) // 对于p > 0时
            {
                z = min(dp[x][p - 1], max(dp[x][p], w[i]));
                if (dp[y][p] > z)
                {
                    dp[y][p] = z;
                    if (sta[y] == 0)
                    {
                        sta[y] = 1;
                        q.push(y);
                    }
                }
            }
        }
    }
}

void solve()
{
    cin >> n >> p >> k;

    for (int i = 1; i <= n; i++)
        h[i] = -1;

    memset(dp, 0x3f, sizeof(dp));

    for (int i = 1; i <= p; i++)
    {
        int x, y, z;
        cin >> x >> y >> z;

        add(x, y, z);
        add(y, x, z);
    }

    spfa();

    int ans = 1e9;
    for (int i = 0; i <= k; i++)
        ans = min(dp[n][i], ans);

    if (ans == 1e9)
        cout << -1 << endl;
    else
        cout << ans << endl;

    return;
}

signed main()
{
    int _;
    // cin >> _;
    _ = 1;
    while (_--)
    {
        solve();
    }
}