[CSP-S 2022] 假期计划
[CSP-S 2022] 假期计划
题目大意
给定一个 $n \leq 2500,m \leq 10000$ 的无向图,有点权。求一条点权和最大的路径 $1\to A\to B\to C\to D\to 1$,满足:
- $A,B,C,D$ 均不为 $1$,且互不相同;
- 每一段路径上经过的点的数量小于等于 $k$。
题目分析
不难想到要通过 bfs 预处理出任意两点间距离。
然后就可以写出一个 $O(nm + n^4)$ 暴力了:直接枚举 $A, B, C, D$ 并判断是否合法。
此时注意到 $n \leq 2.5 \times 10^3$,也就是说:我们至多可以枚举两个点。
于是我们折半一下,预处理对于每个 $B$,所有 $A$(即 $1 \to A \to B$)的最大、次大、次次大的值,求值时枚举 $B, C$ 并统计即可。
时间复杂度为 $O(n(n + m))$。
代码实现
#include <bits/stdc++.h>
#define rint register int
#define endl '\n'
#define int long long
using namespace std;
const int N = 2.5e3 + 5;
const int M = 2e5 + 5;
const int inf = 1e18;
int n, m, k;
int ans;
int h[M], e[M], ne[M], idx;
int dist[N][N], f[N][N], pos[N][3];
int s[N];
queue<int> q;
void add(int a, int b)
{
e[++idx] = b, ne[idx] = h[a], h[a] = idx;
}
void init(int n)
{
for (rint i = 1; i <= n; i++)
{
for (rint j = 1; j <= n; j++)
{
dist[i][j] = inf;
}
}
}
void bfs(int s)
{
dist[s][s] = 0;
q.push(s);
while(!q.empty())
{
int x = q.front();
q.pop();
for (rint i = h[x]; i; i = ne[i])
{
int y = e[i];
if (dist[s][y] == inf)
{
dist[s][y] = dist[s][x] + 1;
q.push(y);
}
}
}
}
signed main()
{
cin >> n >> m >> k;
k += 1;
init(n);
for (rint i = 2; i <= n; i++)
{
cin >> s[i];
}
for (rint i = 1; i <= m; i++)
{
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
}
for (rint i = 1; i <= n; i++)
{
bfs(i);
}
for (rint i = 1; i <= n; i++)
{
for (rint j = 1; j <= n; j++)
{
if (i != j && dist[1][i] <= k && dist[i][j] <= k)
{
f[i][j] = s[i] + s[j];
}
else
{
f[i][j] = -inf;
}
}
}
for (rint i = 2; i <= n; i++)
{
pos[i][1] = i;
pos[i][2] = i;
pos[i][3] = i;
for (rint j = 2; j <= n; j++)
{
if (f[pos[i][1]][i] < f[j][i])
{
pos[i][3] = pos[i][2];
pos[i][2] = pos[i][1];
pos[i][1] = j;
}
else if (f[pos[i][2]][i] < f[j][i])
{
pos[i][3] = pos[i][2];
pos[i][2] = j;
}
else if (f[pos[i][3]][i] < f[j][i])
{
pos[i][3] = j;
}
}
}
for (rint i = 2; i <= n; i++)
{
for (rint j = 2; j <= n; j++)
{
if (i != j && dist[i][j] <= k)
{
for (rint x = 1; x <= 3; x++)
{
for (rint y = 1; y <= 3; y++)
{
if (pos[i][x] != j && pos[i][x] != pos[j][y] && pos[j][y] != i)
{
ans = max(ans, f[pos[i][x]][i] + f[pos[j][y]][j]);
break;
}
}
}
}
}
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号