[ICPC2019上海E] Cave Escape

[ICPC2019上海E] Cave Escape - MST

Description

给定一个 (n∗m) 的格子矩阵,其中有一个格子是起点,一个格子是终点。 从起点开始移动,每次能移动到有相邻边的格子中,每个格子都有一个权值 (v),若从点 ((x,y)) 移动到点 ((i,j)),且 ((i,j)) 点未被访问过,则可以获得 (V_{(x,y)}*V_{(i,j)}) 的收益,若移动到终点,可以选择先不出去。一个点可以重复经过,问能够获得的最大价值是多少?(n,m le 1000, v le 100)

Solution

转化为最大生成树,暴力建图用 Kruskal 即可

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

int x[1000005], fa[1000005], v[1005][1005];
const int di[4] = {0, 0, 1, -1};
const int dj[4] = {1, -1, 0, 0};

void solve()
{
    int n, m, _, a, b, c, p;
    cin >> n >> m >> _ >> _ >> _ >> _ >> x[1] >> x[2] >> a >> b >> c >> p;
    for (int i = 3; i <= n * m; i++)
        x[i] = (a * x[i - 1] + b * x[i - 2] + c) % p;
    vector<vector<pair<int, int>>> buc(p * p + 2);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            for (int dir = 0; dir < 4; dir += 2)
            {
                int ii = i + di[dir], jj = j + dj[dir];
                if (ii == 0 || jj == 0 || ii > n || jj > m)
                    continue;
                buc[x[(i - 1) * m + j] * x[(ii - 1) * m + jj]].push_back(make_pair((i - 1) * m + j, (ii - 1) * m + jj));
            }
        }
    for (int i = 1; i <= n * m; i++)
        fa[i] = i;
    long long ans = 0;
    vector<pair<int, int>> e;
    for (int i = p * p; i >= 0; i--)
    {
        for (auto t : buc[i])
            e.push_back(t);
    }
    function<int(int)> find = [&](int x) -> int {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    };
    for (auto [u, v] : e)
    {
        int uu = find(u);
        int vv = find(v);
        int ww = x[u] * x[v];
        if (uu != vv)
        {
            fa[uu] = vv;
            ans += ww;
        }
    }
    cout << ans << endl;
}

signed main()
{
    int _, t;
    cin >> t;
    for (int _ = 1; _ <= t; _++)
    {
        cout << "Case #" << _ << ": ";
        solve();
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/14571232.html