2024.09.18初赛模拟MX-S/P6029记录

MX-S

太简单了,没啥难度。\yiw
$ 1, 3, 5, 7, 9 $ 的二叉搜索树棵数是卡特兰数。

P6029

题意

给定一张有 $ n $ 个点,$ m $ 条边的图。可以任意交换途中两条边的权值不超过 $ K $ 次,问最后 $ 1 $ 到 $ n $ 的最短路径长度。

$ 1 \le n \le 50 \(,\) 1 \le m \le 150 \(,\) 1 \le K \le 20 $

Solution

这题是某次初赛模拟的时候放上来,似乎比较水,就写了一下。

不难想到一种贪心:直接将所有的最小边能换到路径上就换。

但是这样不一定是最优的,所以考虑枚举最后在路径上的边为所有边中前 $ i $ 小的。

并且用 Dp 在 Dijkstra 的同时计算。

设 $ f_{u, j, k} $ 表示从 $ 1 $ 到 $ u $ 的路径上有 $ j $ 条为前 $ i $ 小的边,且使用了 $ k $ 次交换魔法的最短路径长度。

设当前点为 $ u $,下一个节点为 $ v $,则转移方程如下:

  • 当 $ k + 1 \le K $ 时,$ f_{u, j, k} $ 可以更新 $ f_{v, j, k + 1} $。
  • 当遍历到的 $ (u, v) $ 这条边属于前 $ i $ 条边时,则将这条边边权设为 $ 0 $,并且设 $ j1 = j + 1 $,否则为 $ j $(因为前 $ i $ 条边在最后统一计算前缀和)。此时当 $ j1 \le m $ 时,则可以用 $ f_{u, j, k} + w $ 更新 $ f_{v, j1, k} $。

最后统计答案时,就枚举前 $ i $ 条最小边和 $ j, k $,再处理一个 $ sum $ 表示前 $ i $ 小的边权前缀和,然后在所有 $ f_{n, j, k} + sum $ 中取最小值即可,但是要注意的是枚举条件 $ j + k \le i $。

//Asahina Mafuyu
#include <bits/stdc++.h>

using namespace std;

const int N = 55, M = 155, K = 25;

struct two_plus_four
{
    int id, v, w;
};
struct three_plus_three
{
    int u, j, k, f;
    bool operator < (const three_plus_three & W) const
    {
        return f > W.f;
    }
};

int n, m, k;
int w[M], id[M], mp[M];
int f[N][M][K];
bool st[N][M][K];
vector<two_plus_four> gph[N];

bool cmp(int a, int b)
{
    return w[a] < w[b];
}

void dijkstra(int limit)
{
    memset(f, 0x3f, sizeof f);
    memset(st, 0, sizeof st);
    priority_queue<three_plus_three> q;
    q.push({1, 0, 0, 0});
    f[1][0][0] = 0;
    while (q.size())
    {
        auto t = q.top(); q.pop();
        int u = t.u, j = t.j, K = t.k;
        if (st[u][j][K]) continue;
        st[u][j][K] = 1;
        
        for (auto x : gph[u])
        {
            int v = x.v, w_ = x.w, id_ = x.id, j1 = j;
            if (K < k && f[v][j][K + 1] > f[u][j][K])
            {
                f[v][j][K + 1] = f[u][j][K];
                q.push({v, j, K + 1, f[v][j][K + 1]});
            }
            if (mp[id_] <= limit) j1 ++ , w_ = 0;
            if (j1 <= m && f[v][j1][K] > f[u][j][K] + w_)
            {
                f[v][j1][K] = f[u][j][K] + w_;
                q.push({v, j1, K, f[v][j1][K]});
            }
        }
    }
}

int main()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i ++ )
    {
        int a, b, c;
        cin >> a >> b >> c;
        gph[a].push_back({i, b, c}), gph[b].push_back({i, a, c});
        id[i] = i, w[i] = c;
    }

    sort(id + 1, id + m + 1, cmp);
    sort(w + 1, w + m + 1);
    for (int i = 1; i <= m; i ++ ) mp[id[i]] = i;
    int s = 0, res = 0x3f3f3f3f;
    for (int i = 0; i <= m; i ++ )
    {
        s += w[i];
        dijkstra(i);
        for (int j = 0; j <= i; j ++ )
            for (int K = 0; K <= k && j + K <= i; K ++ )
                res = min(res, f[n][j][K] + s);
    }

    cout << res << '\n';

    return 0;
}
posted @ 2024-09-18 16:21  MafuyuQWQ  阅读(18)  评论(1)    收藏  举报