P8817
欢迎您到我的博客中查看本文,谢谢!
下文中,
-
- 一个点
u 在家附近,意为u 和1 之间可达。
注意,为方便,特殊地,我们认为自己和自己不可达。
观察数据范围,
注意:对于满足边权全为
1 的图,单源最短路可以做到\mathcal{O}(n) 的复杂度(采用 bfs);对于满足边权只有
0 ,1 两种的图,单源最短路也可以做到\mathcal{O}(n) 的复杂度(采用 0-1 bfs)。
我们考虑一条
很直接的想法是,依次考虑
但有一种贪心是对的,那就是确定了
由于环的对称性,可以发现确定了
有了大体思路。
我们定义
第一步:我们预处理出
第二步:直接
发现重复性的细节是存在问题的,比如:会出现
不过,贪心思想还是不变的:
更换定义,
当发现
当发现
发现并没有完全解决:如果这样处理后的
还是贪心思想,考虑把
重复性解决了,但是还有个细节:如果原先
至于原先
如果直接这么写是没有问题的,但是麻烦了。下面是一种更好写的处理方法:
直接分别枚举
需要提前预处理出
注意某些点可达,还在家附近的点数可能没有
如果枚举到某个
题目保证全局上是有解的。
/*
* @Author: crab-in-the-northeast
* @Date: 2022-10-30 17:40:03
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2022-10-30 19:07:52
*/
#include <bits/stdc++.h>
#define int long long
inline int read() {
int x = 0;
bool flag = true;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
flag = false;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
if(flag)
return x;
return ~(x - 1);
}
const int maxn = 2505;
typedef std :: pair <int, int> pii;
std :: vector <int> G[maxn];
int w[maxn];
bool ok[maxn][maxn]; // u, v 是否可达
std :: vector <int> f[maxn]; // f[u] 存放:可达 u 且可达 1 的前三大 v
int k;
int dis[maxn];
void bfs(int x) {
std :: memset(dis, -1, sizeof(dis));
std :: queue <int> q;
q.push(x);
dis[x] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
if (u != x) {
ok[x][u] = true;
if (x != 1 && ok[1][u]) {
// printf("%lld %lld\n", x, u);
f[x].push_back(u);
std :: sort(f[x].begin(), f[x].end(), [](int u, int v) {
return w[u] > w[v];
}); // 注意这里 sort 元素数量不超过 3,效率可看做常数
if (f[x].size() > 3)
f[x].pop_back();
}
}
if (dis[u] == k + 1)
continue;
for (int v : G[u]) if (dis[v] == -1) {
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
inline bool gmx(int &a, int b) {
return b > a ? a = b, true : false;
}
signed main() {
int n = read(), m = read();
k = read();
for (int u = 2; u <= n; ++u)
w[u] = read();
while (m--) {
int u = read(), v = read();
G[u].push_back(v);
G[v].push_back(u);
}
for (int u = 1; u <= n; ++u)
bfs(u);
int ans = 0;
for (int b = 2; b <= n; ++b)
for (int c = 2; c <= n; ++c) if (ok[b][c])
for (int a : f[b])
for (int d : f[c])
if (a != c && b != d && a != d)
// 其他不等关系天然满足了,只有这三组需要检验;
// 天然满足的不等关系:a != b,b != c,c != d,请读者自己思考为什么。
gmx(ans, w[a] + w[b] + w[c] + w[d]);
printf("%lld\n", ans);
return 0;
}
如果觉得这篇题解写得好,请不要忘记点赞,谢谢!