P8817 [CSP-S 2022] 假期计划 解题笔记
给一个不用dp的做法
solution
考虑朴素做法。
预处理出 \(f(x)\),表示距离 \(x\) 不超过 \(k\) 的点。
枚举每个景点 \(a\), \(b\), \(c\), \(d\),通过预处理出的 \(f(x)\) 计算是否合法,更新答案。
这样时间复杂度是 \(O(n ^ 4)\) 的,不能通过本题。
考虑优化。
发现 \(a\) 和 \(d\) 比较特殊,只有距离 \(1\) 在 \(k\) 以内的点才有资格当高贵的点 \(a\) 和点 \(b\)。
而不是所有点与 \(1\) 的距离都小于 \(k\) 。
于是改进一下预处理,新定义 \(f(x)\) 表示与点 \(x\) 的距离不超过 \(k\) 且与 \(1\) 的距离也不超过 \(k\) 的点。
注意到我们选择 \(f(x)\) 是选择最大的 \(f(x)\) 对之后的答案一定没有影响,所以选定 \(a\) 和 \(d\) 时可以使用贪心策略,所以处理 \(f(x)\) 时只用保存最大的 \(f(x)\)。
如果最大的 \(f(x)\) 与 \(c\) 重合或与 \(b\) 重合怎么办?
考虑最坏情况,前二大的 \(f(x)\) 都与 \(c\) 重合或与 \(b\) 重合,那么我们可以保存前三大的 \(f(x)\),这样即使是最坏情况,也能选出 \(a\) 和 \(d\)。
所以总体思路就出来了,暴力枚举 \(b\) 和 \(c\),通过预处理出的 \(f(x)\) 计算 \(a\) 和 \(d\)。
预处理复杂度 \(O(n ^ 2)\),枚举 \(b\) 和 \(c\) 的复杂度 \(O(n ^ 2)\),计算 \(a\) 和 \(d\) 的复杂度 \(O(1)\),总时间复杂度为 \(O(n ^ 2)\),足以通过本题。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int QWQ = 2505;
int n, m, k, a[QWQ], dis[QWQ];
int maxx = -2e18;
bool can[QWQ][QWQ];
vector<int> ve[QWQ];
vector<int> qwq[QWQ];
void bfs(int start)
{
memset(dis, -1, sizeof(dis));
queue<int> q;
q.push(start);
dis[start] = 0;
while (!q.empty())
{
int u = q.front();
q.pop();
if (dis[u] > k + 1)
continue;
can[start][u] = true;
for (int i = 0; i < ve[u].size(); i++)
{
int to = ve[u][i];
if (dis[to] == -1)
{
dis[to] = dis[u] + 1;
q.push(to);
}
}
}
}
bool cmp(int x, int y)
{
return a[x] > a[y];
}
signed main()
{
cin >> n >> m >> k;
for (int i = 2; i <= n; i++)
{
cin >> a[i];
}
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
ve[u].push_back(v);
ve[v].push_back(u);
}
memset(can, false, sizeof(can));
for (int i = 1; i <= n; i++)
{
bfs(i);
}
for (int i = 2; i <= n; i++)
{
for (int j = 2; j <= n; j++)
{
if (i == j)
continue;
if (can[1][j] && can[j][i])
{
qwq[i].push_back(j);
}
}
sort(qwq[i].begin(), qwq[i].end(), cmp);
if (qwq[i].size() > 3)
{
qwq[i].resize(3);
}
}
for (int b = 2; b <= n; b++)
{
for (int c = 2; c <= n; c++)
{
if (b == c || !can[b][c])
continue;
for (int i = 0; i < qwq[b].size(); i++)
{
int aa = qwq[b][i];
if (aa == b || aa == c)
continue;
for (int qaq = 0; qaq < qwq[c].size(); qaq++)
{
int dd = qwq[c][qaq];
if (dd == aa || dd == b || dd == c)
continue;
if (can[1][aa] && can[aa][b] && can[b][c] && can[c][dd] && can[dd][1])
{
int total = a[aa] + a[b] + a[c] + a[dd];
maxx = max(maxx, total);
}
}
}
}
}
cout << maxx << endl;
}

浙公网安备 33010602011771号