2022 CCF CSP-S2.假期计划

发布于:2025-04-07 ⋅ 阅读:(30) ⋅ 点赞:(0)

题目

4732. 假期计划
在这里插入图片描述

算法标签: 搜索, 枚举, 贪心

思路

最多转车 k k k次等价于路线长度小于等于 k + 1 k + 1 k+1, 经过的点没有限制, 注意到点的数量 2500 2500 2500, 因此 n 2 n ^ 2 n2的时间复杂度是可以考虑的, 边的数量 10000 10000 10000, n × m n \times m n×m时间复杂度也可以接受, 相当于从每个点预处理一遍, 可以预处理出每个点到其他所有点的最短距离, 也可以预处理出每个点在 k + 1 k + 1 k+1长度之内能到达的点
只能枚举两个点, 可以考虑枚举 b , c b, c b,c两个点, 可以将所有方案分为 A n − 1 2 A_{n - 1} ^ 2 An12

在这里插入图片描述
在这里插入图片描述
a , d a, d a,d两个点距离 1 1 1的距离都不能超过 k + 1 k + 1 k+1其实是属于一种限制, 因此 f [ x ] f[x] f[x]表示所有与 1 1 1不超过 k + 1 k + 1 k+1的点集以及所有与 x x x不超过 k + 1 k + 1 k+1的不是 x x x的点集, 因为预处理是从小到大, 因此 v i s [ 1 ] [ x ] vis[1][x] vis[1][x]会首先处理, 后续判断直接查表
在这里插入图片描述

枚举 b , c b, c b,c之后确定的关系是黑色线段, 但是要求每个景点是不同的, 因此对于点 a a a还需要判断是否和 c c c或者 d d d相同, 对于点 b b b仍需要判断是否和 d d d相同

直接枚举的时间复杂是 O ( n 4 ) O(n ^ 4) O(n4)是无法接受的, 因此需要进行优化, 注意到对于点 a a a来说, 只需要和 c , d c, d c,d两个点不同就可以, 因此只需要找出 a a a能到达的最大的三个值参与贡献, 对于点 d d d也是同样的道理, 这样就能将 n 2 n ^ 2 n2优化到 9 9 9

优化后时间复杂度 O ( n 2 + 9 × n 2 ) O(n ^ 2 + 9 \times n ^ 2) O(n2+9×n2)

插入排序写法

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

typedef long long LL;
const int N = 2510, M = 20010;

int n, m, k;
LL w[N];
vector<int> head[N];
int d[N], f[N][4];
bool vis[N][N];

void add(int u, int v) {
	head[u].push_back(v);
}

void bfs(int s, int f[]) {
	int q[N];
	int h = 0, t = -1;
	memset(d, 0x3f, sizeof d);
	d[s] = 0;
	q[++t] = s;

	while (h <= t) {
		int u = q[h++];
		if (d[u] == k + 1) continue;

		for (int v : head[u]) {
			if (d[u] + 1 < d[v]) {
				d[v] = d[u] + 1;
				vis[s][v] = true;
				q[++t] = v;

				if (vis[1][v]) {
					f[3] = v;
					for (int i = 3; i; --i) {
						if (w[f[i]] > w[f[i - 1]]) swap(f[i], f[i - 1]);
						else break;
					}
				}
			}
		}
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	cin >> n >> m >> k;
	for (int i = 2; i <= n; ++i) cin >> w[i];

	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		add(u, v);
		add(v, u);
	}

	for (int i = 1; i <= n; ++i) bfs(i, f[i]);

	LL ans = 0;
	// 枚举b, c两个点
	for (int b = 2; b <= n; ++b) {
		for (int c = 2; c <= n; ++c) {
			if (vis[b][c]) {
				for (int x = 0; x < 3; ++x) {
					for (int y = 0; y < 3; ++y) {
						int a = f[b][x], d = f[c][y];
						if (a && d && a != d && a != c && b != d) {
							ans = max(ans, w[a] + w[b] + w[c] + w[d]);
						}
					}
				}
			}
		}
	}

	cout << ans << "\n";
	return 0;
}

s o r t sort sort写法

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

typedef long long LL;
const int N = 2510, M = 20010;

int n, m, k;
LL w[N];
vector<int> head[N];
int d[N], f[N][4];
bool vis[N][N];

void add(int u, int v) {
	head[u].push_back(v);
}

bool cmp(const int a, const int b) {
	return w[a] > w[b];
}

void bfs(int s, int f[]) {
	int q[N];
	int h = 0, t = -1;
	memset(d, 0x3f, sizeof d);
	d[s] = 0;
	q[++t] = s;

	while (h <= t) {
		int u = q[h++];
		if (d[u] == k + 1) continue;

		for (int v : head[u]) {
			if (d[u] + 1 < d[v]) {
				d[v] = d[u] + 1;
				vis[s][v] = true;
				q[++t] = v;

				if (vis[1][v]) {
					f[3] = v;
					sort(f, f + 4, cmp);
				}
			}
		}
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	cin >> n >> m >> k;
	for (int i = 2; i <= n; ++i) cin >> w[i];

	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		add(u, v);
		add(v, u);
	}

	for (int i = 1; i <= n; ++i) bfs(i, f[i]);

	LL ans = 0;
	// 枚举b, c两个点
	for (int b = 2; b <= n; ++b) {
		for (int c = 2; c <= n; ++c) {
			if (vis[b][c]) {
				for (int x = 0; x < 3; ++x) {
					for (int y = 0; y < 3; ++y) {
						int a = f[b][x], d = f[c][y];
						if (a && d && a != d && a != c && b != d) {
							ans = max(ans, w[a] + w[b] + w[c] + w[d]);
						}
					}
				}
			}
		}
	}

	cout << ans << "\n";
	return 0;
}