首页 > 其他分享 >[CSP-S 2022] 假期计划 题解

[CSP-S 2022] 假期计划 题解

时间:2022-12-18 19:11:27浏览次数:72  
标签:dist int 题解 点权 choice 2022 CSP rightarrow

题面

题面冗长,不便展示,详见 洛谷

考场想法

对于每一个点给他能到达的点都建一条边,最后跑一遍 DFS。期望分数:\(60\)。

代码

朴素想法

枚举所有可能的四个点,看是否能 “互通有无”,如果可以就更新最终答案。

时间复杂度:\(O(n^4)\)

期望分数:\(55\)。

正解思路

优化朴素想法,其实我们可以进行贪心考虑。

预处理

说在前面,可以预处理出来一个点是否能够到达另一个点,由于边权都是 \(1\),因此用 BFS 可实现,即从每个点开始遍历,能遍历到的点都记为可到达,时间复杂度:\(O(nm)\),可接受。

贪心

不妨设当前的路径是:\(1\rightarrow a\rightarrow b\rightarrow c\rightarrow d\rightarrow 1\)。

发现在考虑\(1\rightarrow a\rightarrow b\rightarrow c\rightarrow ?\rightarrow 1\) 的时候,可以贪心地找到 \(c\rightarrow 1\) 之间可行的点权最大的点,将其作为 \(d\)。

对应地,在考虑 \(1\rightarrow ?\rightarrow b\rightarrow c\rightarrow d\rightarrow 1\) 的时候,也可以这么贪心出 \(a\)。

于是想到,有没有可能只需要枚举 \(b\) 和 \(c\) 就可以了呢?答案是肯定的!(只不过需要判断一下 \(b\) 与 \(c\) 是否可达)

结合之前的想法,整个问题就基本解决了,让我们捋一下思路:

  1. 二重循环确定 \(b, c\);
  2. 找到 \(1\rightarrow b\) 与 \(c\rightarrow 1\) 之间的可行点权最大者,将其分别置为 \(a, d\);
  3. 输出答案,完美撒花~

噢噢,看起来这样就可以了呢,让我们来实现以下吧——

可以了吗?(贪心中的纰漏)

注意,实际操作的时候 \(a, b, c, d\) 这四个点是有可能重复的,这样就不行了。

哦我的老伙计,那我们该怎么办呢!

答案是:给 \(a, d\) 两个点存三个可能的备胎,这样即使发生:

\(a\) 与 \(c\) 重合了,换完了又与 \(d\) 重合了

的情况也不怕,换上第三个备胎就好了,对于 \(d\) 同理。

如果这样实现有些许麻烦,可以这么做:

枚举所有可能的备胎组合情况,取四个点都不重的情况中的点权和最大值。

这样省去了许多判断,更简洁优美。

形式化地说:预处理出这,么一个数组:\(choice[i][j](j\in\{0, 1, 2\})\),表示点 \(i\) 和点 \(1\) 同时可达的点中,点权第 \(j + 1\) 大的点。

需要注意,可能点 \(i\) 和点 \(1\) 同时可达的点不足三个,这时候 \(j\) 取不到 \(2\),可能产生越界,有很多方式避免他,这里我选择用 vector 类型存储 choice[][]

结合之前的想法,整个问题就正式解决了,让我们捋一下思路:

  1. 二重循环确定 \(b, c\);
  2. 枚举所有可能的 \(choice[b][]\) 与 \(choice[c][]\),作为 \(a, d\),判断四个点 \(a,b,c,d\) 是否重合,如果不重合就统计他的点权和并与当前答案比较;
  3. 输出答案,完美撒花~

参考代码

// 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;
}

标签:dist,int,题解,点权,choice,2022,CSP,rightarrow
From: https://www.cnblogs.com/MoyouSayuki/p/16990782.html

相关文章

  • 题解 [ABC133F] Colorful Tree
    原题链接考虑正常的\(u\)和\(v\)之间的距离怎么去求:我们可以维护每个值到根的距离\(dist_i\),然后通过计算\(dist_u+dist_v-2\timesdist_{lca}\)得到,这里就不过......
  • 2022全国高校计算机能力挑战赛区域赛python组编程题
    互联网的意义在于高质量的共享编程题1.快递行业的兴起慢慢的改变了人们的生活方式,越来越多的人选择了快递的方式。列表LA和列表LB中分别存放了一位快递小哥今年9月份每......
  • IDEA中Maven项目 子项目中缺少parent标签及无web框架问题解决
    Question在maven项目中,创建的子模块的pom中没有标签,但父模块中有,造成运行时提示版本源过低原因:maven的settings.xml中默认jdk版本过低解决方法:在maven中指定jdk版本,找到......
  • 20221325 实验七-实验报告
    一、实验简介缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况。这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段。这一漏洞的出现......
  • ICPC2022杭州站(补题)
    A-ModuloRuinstheLegend#include<bits/stdc++.h>#definelllonglongusingnamespacestd;lln,m,sum,n1,n2;llGcd(lla,llb){if(!b)returna;ret......
  • 2022.51 ChatGPT
    1966年,第一代聊天机器人问世,依托代码生成的规则运行,仅仅通过提取关键词并以固定方式重组与人对话(简单的特点),这一阶段持续到了2010年;2011年,人类迎来了以机器学习技术为核心......
  • [ABC282D] Make Bipartite 2 题解
    题目描述给定一个无向简单图\(G\),统计有多少个点对\((u,v)\)满足:\(u,v\)之间没有边直接连接:\((u,v)\notin\textE\)连接\((u,v)\)后\(G\)是二分图......
  • USACO2022铜组游记
    Day0休息了一会儿,看了看书,准备开始。Day1 9:00的钟声敲响了,开始考试。第一题是一道模拟题,但需要优化,差点TLE。正要交时突然想起来教练说要加freopen......
  • C语言《程序设计课程设计》[2022-12]
    C语言《程序设计课程设计》[2022-12]程序设计课程设计说明书一、设计任务与要求《程序设计课程设计》是在完成《C语言程序设计》课程学习后进行的一门专业实践课程,是培......
  • NOIP2022 游记(by Fy5Fengye)
    Day-x,11.?马上就是联赛了,不紧张是不现实的。每天都是模拟赛,每天都被爆锤……但是只要我没有心,就莫得心态问题!=)Day-7~-1,11.18~11.24联赛前一周。已经很难学进去什么......