CSP-S 2022 T1假期计划

news/2025/2/28 23:35:09/

CSP-S 2022 T1假期计划

先思考暴力做法,题目需要找到四个不相同的景点,那我们就枚举这四个景点,判断它们之间的距离是否符合条件,条件是任意两个点之间的距离是否大于 k k k,所以我们需要求出任意两点之间的距离。常用的 D i j k s t r a Dijkstra Dijkstra S P F A SPFA SPFA都是单源最短路,也就是只能求一个点到其它点的距离,而 F l o y e d Floyed Floyed可以求任意两个点之间的最短路,虽然其时间复杂度是 O ( n 3 ) O(n^3) O(n3),但对于这个做法的数据范围是可以接受的。这个做法的时间复杂度为 O ( n 4 ) O(n^4) O(n4)(枚举四个景点),在 k k k较小的情况下可以通过(因为 k k k会影响到循环退出),可以拿到 55 55 55分。

#include <bits/stdc++.h>
#define A 2510using namespace std;
typedef long long ll;
int n, m, kk, x, y, dis[A][A];
ll a[A], ans;int main(int argc, char const *argv[]) {scanf("%d%d%d", &n, &m, &kk); kk++;for (int i = 2; i <= n; i++) scanf("%lld", &a[i]);memset(dis, 0x3f, sizeof dis);for (int i = 1; i <= n; i++) dis[i][i] = 0;for (int i = 1; i <= m; i++) {scanf("%d%d", &x, &y);dis[x][y] = 1; dis[y][x] = 1;}for (int k = 1; k <= n; k++)for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);for (int i = 2; i <= n; i++) {if (dis[1][i] > kk) continue;for (int j = 2; j <= n; j++) {if (i == j) continue;if (dis[i][j] > kk) continue;for (int k = 2; k <= n; k++) {if (i == k or j == k) continue;if (dis[j][k] > kk) continue;for (int l = 2; l <= n; l++) {if (i == l or j == l or k == l) continue;if (dis[k][l] > kk or dis[l][1] > kk) continue;ans = max(ans, a[i] + a[j] + a[k] + a[l]);}}}}printf("%lld\n", ans);
}

比较特殊的数据点是当 k = 0 k=0 k=0时,也就是挑选的 4 4 4个景点必须都相邻,直接通过 d f s dfs dfs搜索所有的情况,如果遍历到了家( 1 1 1号点)并且已经路过了 4 4 4个不同的节点,这就是一条可行的路径,可以更新答案。 k = 0 k=0 k=0共有 9 9 9个测试点,共 45 45 45分。

#include <bits/stdc++.h>
#define A 2510using namespace std;
int n, m, k, a[A], ans;
bool vis[A], mp[A][A];
void dfs(int now, int sum, int left) {if (now == 1 and left == 0) {ans = max(ans, sum);return;}else if (left == 0) return;for (int i = 1; i <= n; i++) {if (!mp[now][i] or vis[i]) continue;vis[i] = 1;dfs(i, sum + a[i], left - 1);vis[i] = 0;}
}int main() {cin >> n >> m >> k;for (int i = 2; i <= n; i++) cin >> a[i];while (m--) {int x, y;cin >> x >> y;mp[x][y] = 1; mp[y][x] = 1;}dfs(1, 0, 5);cout << ans << endl;
}

这个写法可以通过 k = 0 k=0 k=0的所有特殊情况,和第一个暴力结合一下,可以拿到 70 70 70分。

#include <bits/stdc++.h>
#define A 2510using namespace std;
typedef long long ll;
int n, m, kk, x, y, dis[A][A];
ll a[A], ans;
bool vis[A], mp[A][A];
void dfs(int now, ll sum, int left) {if (now == 1 and left == 0) {ans = max(ans, sum);return;}else if (left == 0) return;for (int i = 1; i <= n; i++) {if (!mp[now][i] or vis[i]) continue;vis[i] = 1;dfs(i, sum + a[i], left - 1);vis[i] = 0;}
}int main(int argc, char const *argv[]) {scanf("%d%d%d", &n, &m, &kk);if (kk == 0) {for (int i = 2; i <= n; i++) scanf("%lld", &a[i]);while (m--) {scanf("%d%d", &x, &y);mp[x][y] = 1; mp[y][x] = 1;}dfs(1, 0, 5);printf("%lld\n", ans);return 0;}kk++;for (int i = 2; i <= n; i++) scanf("%lld", &a[i]);memset(dis, 0x3f, sizeof dis);for (int i = 1; i <= n; i++) dis[i][i] = 0;for (int i = 1; i <= m; i++) {scanf("%d%d", &x, &y);dis[x][y] = 1; dis[y][x] = 1;}for (int k = 1; k <= n; k++)for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);for (int i = 2; i <= n; i++) {if (dis[1][i] > kk) continue;for (int j = 2; j <= n; j++) {if (i == j) continue;if (dis[i][j] > kk) continue;for (int k = 2; k <= n; k++) {if (i == k or j == k) continue;if (dis[j][k] > kk) continue;for (int l = 2; l <= n; l++) {if (i == l or j == l or k == l) continue;if (dis[k][l] > kk or dis[l][1] > kk) continue;ans = max(ans, a[i] + a[j] + a[k] + a[l]);}}}}printf("%lld\n", ans);
}

我们要找的一个路径是 1 → A → B → C → D → 1 1\to A\to B\to C\to D\to 1 1ABCD1,可以发现其中 A A A D D D B B B C C C有一些共同之处: A A A D D D的两端一定是起点 1 1 1和一个其它的点,由于道路是双向的,所以可以说 A A A D D D这两个点是等价的; B B B D D D的两端一定是非起点,可以说 B B B C C C这两个点是等价的。这样一来中间不同的四个点被压缩成了两个点。
用一个双重循环枚举 A A A B B B A A A B B B点的特征是 d i s [ 1 ] [ A ] < k dis[1][A]<k dis[1][A]<k d i s [ A ] [ B ] < k dis[A][B]<k dis[A][B]<k,同时满足条件的点 A A A也对应着点 D D D,点 B B B对应着点 C C C。对于所有的点 B B B,找到所有符合条件的点 A A A,符合条件的点 A A A可能有很多,我们只需要存值最大的三个就可以。

为什么是存三个点?
对于路径 1 → A → B → C → D → 1 1\to A\to B\to C\to D\to 1 1ABCD1,假设枚举点 B B B时找到了点 j j j作为 A A A点,枚举点 C C C时找到了点 k k k作为 D D D点,那么 k = j k=j k=j k = B k=B k=B都是有可能发生的,所以要存三个点以防重复。

#include <bits/stdc++.h>using namespace std;
typedef long long ll;
#define A 2510
vector<int> e[A];
ll dis[A][A], ans, a[A];
bool vis[A];
int n, m, k;
void bfs(int start) {memset(vis, 0, sizeof vis); vis[start] = 1;queue<int> q; q.push(start);while (!q.empty()) {int fr = q.front(); q.pop();for (int i = 0; i < (int)e[fr].size(); i++) {int ca = e[fr][i];if (vis[ca]) continue;vis[ca] = 1;if (dis[start][ca] > dis[start][fr] + 1) {dis[start][ca] = dis[start][fr] + 1;q.push(ca);}}}
}
set<pair<ll, int> > s[A];int main(int argc, char const *argv[]) {scanf("%d%d%d", &n, &m, &k); k++;for (int i = 2; i <= n; i++) scanf("%lld", &a[i]);while (m--) {int x, y; scanf("%d%d", &x, &y);e[x].push_back(y); e[y].push_back(x);}for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) {dis[i][j] = INT_MAX;if (i == j) dis[i][j] = 0;}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 and dis[j][i] <= k and dis[1][j] <= k) {s[i].insert(make_pair(a[j], j));if (s[i].size() > 3) s[i].erase(s[i].begin());}}for (int i = 2; i <= n; i++)for (int j = 2; j <= n; j++) {if (dis[i][j] > k or i == j) continue;for (auto k : s[i]) {if (k.second == i or k.second == j) continue;for (auto l : s[j]) {if (l.second == i or l.second == j or l.second == k.second) continue;ans = max(ans, a[i] + a[j] + a[l.second] + a[k.second]);}}}cout << ans << endl;
}

http://www.ppmy.cn/news/1575623.html

相关文章

【Java项目】基于Spring Boot的旅游管理系统

【Java项目】基于Spring Boot的旅游管理系统 技术简介&#xff1a;采用Java技术、Spring Boot框架、MySQL数据库等实现。 系统简介&#xff1a;旅游管理系统是一个基于Web的在线平台&#xff0c;主要分为前台和后台两大功能模块。前台功能模块包括&#xff08;1&#xff09;首…

Redis-列表结构实操

列表实操 前言简单练习基本的LPUSH和RPUSH操作列表元素的访问与修改列表元素的插入和删除列表阻塞操作 困难练习分页列表游标机制业务上考虑直接访问任意页如何高效分页局限性小结 实现限时排行版轮换消息队列可靠性实现分布式锁实现 总结 前言 之前总结过-列表的数据结构,但是…

go 查看版本

个人学习笔记 1. 打开终端&#xff08;或命令提示符&#xff09; 在 Windows 上&#xff0c;使用 cmd 或 PowerShell。在 macOS 或 Linux 上&#xff0c;使用终端应用程序。 2. 运行以下命令 go version 3. 查看输出 命令执行后&#xff0c;终端会显示已安装的 Go 版本&…

JAVA【微服务】Spring AI 使用详解

目录 一、前言二、Spring AI 概述2.1 什么是 Spring AI2.2 Spring AI 特点2.3 Spring AI 带来的便利2.4 Spring AI 应用领域2.4.1 聊天模型2.4.2 文本到图像模型2.4.3 音频转文本2.4.4 嵌入大模型使用2.4.5 矢量数据库支持2.4.6 数据工程 ETL 框架三、Spring AI 对接 ChatGPT3.…

设计模式-(装饰器,适配器,观察者,外观)

装饰器模式 概念&#xff1a; 它允许在不改变对象自身的情况下&#xff0c;动态地给对象添加额外的功能。通过使用装饰器模式&#xff0c;可以在运行时对对象进行扩展&#xff0c;而不需要创建大量的子类 应用&#xff1a; 当你希望在不修改原有类的情况下&#xff0c;给对…

软件测试丨计算机视觉场景下的边缘计算与测试场景

在计算机视觉场景中&#xff0c;边缘计算与测试场景的结合具有重要意义。以下是两者的关键点&#xff1a; 1. 边缘计算在计算机视觉中的作用 边缘计算将计算任务从云端转移到靠近数据源的边缘设备&#xff0c;如摄像头、传感器等&#xff0c;具有以下优势&#xff1a; 低延迟…

北京大学DeepSeek与AIGC应用(PDF无套路下载)

近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大模型和生成式AI&#xff08;AIGC&#xff09;的突破&#xff0c;正在重塑各行各业的生产方式与创新路径。 北京大学联合DeepSeek团队推出的内部研讨教程《DeepSeek与AIGC应用》&#xff0c;以通俗易懂的方式系统解…

Linux的部分常用基础指令

目录 1. ls 指令 2. pwd命令 3. cd 指令 4. touch 指令 5. mkdir指令 6. rmdir指令&&rm指令 7. rm命令可以同时删除文件或目录 8. man指令 9. cp指令 10. mv指令 11. cat 指令 12. more指令 13. less 指令 14. head指令 15. tail 指令 16. find 指令 17. whi…