[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();
}
}