[CSP-S 2022] 假期计划 题解
题面
题面冗长,不便展示,详见 洛谷。
考场想法
对于每一个点给他能到达的点都建一条边,最后跑一遍 DFS
。期望分数:
朴素想法
枚举所有可能的四个点,看是否能 “互通有无”,如果可以就更新最终答案。
时间复杂度:
期望分数:
正解思路
优化朴素想法,其实我们可以进行贪心考虑。
预处理
说在前面,可以预处理出来一个点是否能够到达另一个点,由于边权都是 BFS
可实现,即从每个点开始遍历,能遍历到的点都记为可到达,时间复杂度:
贪心
不妨设当前的路径是:
发现在考虑
对应地,在考虑
于是想到,有没有可能只需要枚举
结合之前的想法,整个问题就基本解决了,让我们捋一下思路:
- 二重循环确定
; - 找到
与 之间的可行点权最大者,将其分别置为 ; - 输出答案,完美撒花~
噢噢,看起来这样就可以了呢,让我们来实现一下吧——
可以了吗?(贪心中的纰漏)
注意,实际操作的时候
哦我的老伙计,那我们该怎么办呢!
答案是:给
与 重合了,换完了又与 重合了
的情况也不怕,换上第三个备胎就好了,对于
如果这样实现有些许麻烦,可以这么做:
枚举所有可能的备胎组合情况,取四个点都不重的情况中的点权和最大值。
这样省去了许多判断,更简洁优美。
形式化地说:预处理出这,么一个数组:
需要注意,可能点 vector
类型存储 choice[][]
。
结合之前的想法,整个问题就正式解决了,让我们捋一下思路:
- 二重循环确定
; - 枚举所有可能的
与 ,作为 ,判断四个点 是否重合,如果不重合就统计他的点权和并与当前答案比较; - 输出答案,完美撒花~
参考代码
// Problem: P8817 [CSP-S 2022] 假期计划
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P8817
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// Author: Moyou
// Copyright (c) 2022 Moyou All rights reserved.
// Date: 2022-12-18 17:33:37
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
const int N = 2510;
int score[N]; // 点权
bool pass[N][N]; // 记录两点是否可达
int n, m, k;
vector<int> g[N]; // 图
vector<int> choice[N]; // 备胎们
void init()
{
cin >> n >> m >> k;
for (int i = 2; i <= n; i++)
cin >> score[i];
for (int i = 1; i <= m; i++)
{
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
}
void bfs(int s)
{
int dist[N];
memset(dist, 0x3f, sizeof dist);
dist[s] = 0;
queue<int> q;
q.push(s);
while (q.size())
{
auto t = q.front();
q.pop();
if (s != t)
{
pass[s][t] = 1;
if (s != 1 && pass[1][t])
{
choice[s].push_back(t);
sort(choice[s].begin(), choice[s].end(),
[](int a, int b)
{
return score[a] > score[b];
});
if (choice[s].size() > 3) // 不可超了
choice[s].pop_back();
}
}
if (dist[t] == k + 1) // 超出可达的范围
continue;
for (auto i : g[t])
if (dist[i] > dist[t] + 1)
dist[i] = dist[t] + 1, q.push(i);
}
}
int mx = -INF;
bool diff(int a, int b, int c, int d)
{
return a != c && b != d && a != d;
}
signed main()
{
init();
for (int i = 1; i <= n; i++)
bfs(i);
for (int b = 2; b <= n; b++)
for (int c = 2; c <= n; c++)
if (pass[b][c] && b != c)
for (auto i : choice[b])
for (auto j : choice[c])
if (diff(i, b, c, j))
mx = max(mx, score[b] + score[c]
+ score[i] + score[j]);
cout << mx << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现