2021 RoboCom 世界机器人开发者大赛-本科组(复赛)解题报告 | 珂学家

前言

在这里插入图片描述


题解

睿抗机器人开发者大赛CAIP-编程技能赛-历年真题 汇总

2021 RoboCom 世界机器人开发者大赛-本科组(复赛)解题报告

感觉这个T1特别有意思,非典型题,着重推演下结论。

T2是一道玄学题,但是涉及一些优化技巧。

T3这类题,vp的价值并不大,但是符合睿抗的出题风格。

T4是睿抗特别喜欢的最短路径题,但是一来题目有坑点,二来真的太耗时间了,T_T。


7-1 冒险者分队

分值: 20分

思路:解方程组 + 中位数定律

题意省流:

三个数a, b, c 通过如下操作变为 d, e, f

  1. 选择某个数+40,其余两数-20
  2. 选择某个数-40,其余两数+20

求最小的操作步骤数,如不存在则返回-1


这类贪心题挺难,如何证明,以及写对挺难得。

前置论点:

  • 某个数不可能同时存在+40,又-40的操作,因为两两抵消属于无用功,要满足最小步骤,必然只有一个操作方向
  • a + b + c = d + e + f

令x1,x2,x3分别为a,b,c对应40的操作次数,(x1,x2,x3∈Z){令x_1,x_2,x_3分别为a, b, c 对应40的操作次数, (x_1, x_2, x_3 \in Z) }x1x2x3分别为a,b,c对应40的操作次数,(x1,x2,x3Z)

  • 若xk>0,说明+40操作xk次{若 x_k > 0, 说明 +40操作 x_k次}xk>0,说明+40操作xk
  • 若xk<0,说明−40操作∣xk∣次{若 x_k < 0, 说明 -40操作 |x_k|次}xk<0,说明40操作xk

构建对应的三元一次方程组,

{40x1−20x2−20x3=d−a=y1−20x1+40x2−20x3=e−b=y2−20x1−20x2+40x3=f−c=y3\left\{\begin{matrix} 40x_1 - 20x_2 - 20x_3 = d - a = y_1\\ -20x_1 + 40x_2 - 20x_3 = e - b = y_2\\ -20x_1 - 20x_2 + 40x_3 = f - c = y_3 \end{matrix}\right. 40x120x220x3=da=y120x1+40x220x3=eb=y220x120x2+40x3=fc=y3

求f(x1,x2,x3)=∣x1∣+∣x2∣+∣x3∣最小求 f(x_1, x_2, x_3) = |x_1| + |x_2| + |x_3| 最小 f(x1,x2,x3)=x1+x2+x3最小

该方程组的秩为2,没法解, 但是可以把x1,x2表示为x3的形态x_1, x_2表示为x_3的形态x1,x2表示为x3的形态

方程组进行变换为,可求得

{x1=(2y1+y2)/60+x3x2=(2y2+y1)/60+x3\left\{\begin{matrix} x_1 = (2y_1 + y_2) / 60 + x_3 \\ x_2 = (2y_2+y_1) / 60 + x_3 \end{matrix}\right. {x1=(2y1+y2)/60+x3x2=(2y2+y1)/60+x3

进而
f(x1,x2,x3)=∣x1∣+∣x2∣+∣x3∣f(x_1,x_2, x_3) = |x_1| + |x_2| + |x_3| f(x1,x2,x3)=x1+x2+x3
⇒f(x1,x2,x3)=∣x3+(2y1+y2)/60∣+∣x3+(2y2+y1)/60∣+∣x3∣\Rightarrow f(x_1,x_2, x_3) = |x_3+(2y_1 + y_2) / 60| + |x_3 + (2y_2+y_1) / 60| + |x_3| f(x1,x2,x3)=x3+(2y1+y2)/60∣+x3+(2y2+y1)/60∣+x3
⇒f(x1,x2,x3)=∣x3−z1∣+∣x3−z2∣+∣x3−z3∣\Rightarrow f(x_1,x_2, x_3) = |x_3- z_1| + |x_3 - z_2| + |x_3 - z_3| f(x1,x2,x3)=x3z1+x3z2+x3z3

求这个得最小值,不就是 中位数定律 吗?

z1=−(2y1+y2)/60,z2=−(2y2+y1)/60,z3=0三个数的中间值,带入f(x1,x2,x3)即可{ z_1=-(2y_1 + y_2) / 60 , z_2=-(2y_2+y_1) / 60, z_3=0 } 三个数的中间值,带入f(x_1, x_2, x_3) 即可z1=(2y1+y2)/60,z2=(2y2+y1)/60,z3=0三个数的中间值,带入f(x1,x2,x3)即可

当然这边的额外条件是

保证 −(2y1+y2)/60,−(2y2+y1)/60-(2y_1 + y_2) / 60 , -(2y_2+y_1) / 60(2y1+y2)/60,(2y2+y1)/60 需为整数

#include <bits/stdc++.h>using namespace std;int64_t median(int64_t a, int64_t b, int64_t c, int64_t x) {return abs(x - a) + abs(x - b) + abs(x - c);
}int main() {int t;cin >> t;while (t-- > 0) {int64_t a, b, c;int64_t d, e, f;cin >> a >> b >> c;cin >> d >> e >> f;if (a + b + c != d + e + f) {cout << -1 << "\n";continue;}int64_t y1 = d - a;int64_t y2 = e - b;if ((2*y1 + y2) % 60 != 0 || (2 * y2 + y1) % 60 != 0) {cout << -1 << "\n";continue;}// 方程组求解int64_t z1 = (2 * y1 + y2) / 60;int64_t z2 = (2 * y2 + y1) / 60;vector<int64_t> tmp = {-z1, -z2, 0};sort(tmp.begin(), tmp.end());// 中位数定律int64_t res = median(-z1, -z2, 0, tmp[1]); // tmp[1]为中点cout << res << "\n";}return 0;
}

7-2 拼题A打卡奖励

思路: 0-1背包

时间复杂度O(N∗M)=O(365∗24∗60∗1000)=O(5∗108)O(N*M)=O(365*24*60*1000)=O(5*10^8)O(NM)=O(36524601000)=O(5108)

#include <bits/stdc++.h>using namespace std;int main() {int n, M;cin >> n >> M;vector<int> arr(n), brr(n);for (int &x: arr) cin >> x;for (int &x: brr) cin >> x;vector<int> dp(M + 1);for (int i = 0; i < n; i++) {for (int j = M - arr[i]; j >= 0; j--) {dp[j+arr[i]] = max(dp[j+arr[i]], dp[j] + brr[i]);}}cout << *max_element(dp.begin(), dp.end()) << "\n";return 0;
}

纯数组的0-1背包,其实是可以直接冲的。

这题的玄就在玄在:

  • g++提交,tle
  • clang++提交, ac

在这里插入图片描述
那这题关键点在于什么呢?

  1. 每次打卡花费的时间为mi≤600m_i \le 600mi600

即总的容量为: Q=min(n∗600,M){Q = min(n*600, M)}Q=min(n600,M),时间复杂度变为 O(n∗Q)O(n*Q)O(nQ),存在收益

  1. 压缩容量遍历(尤其是早期)

可以对打卡时间从小到大排序,然后容量上限逐步提高

#include <bits/stdc++.h>using namespace std;int main() {int n, M;cin >> n >> M;vector<array<int,2>> cards(n);for (int i = 0; i < n; i++) {cin >> cards[i][0];}for (int i = 0; i < n; i++) {cin >> cards[i][1];}// 第一个优化点int Q = min(n * 600, M);vector<int> dp(Q + 1);// 第二个优化点, 按时间从小到大排序sort(cards.begin(), cards.end(), [](auto &a, auto &b) {return a[0] < b[0];});int tot = 0;for (int i = 0; i < n; i++) {int v = cards[i][0], w = cards[i][1];// 逐步放大范围tot = min(tot + v, Q);for (int j = tot - v; j >= 0; j--) {dp[j+v] = max(dp[j+v], dp[j] + w);}}cout << *max_element(dp.begin(), dp.end()) << "\n";return 0;
}

结果对比:
在这里插入图片描述


7-3 快递装箱

分值: 25分
思路: 建模+模拟
知识点: 双端队列
前置的知识点:

  • 一个数组,整体右移一位,其实是需要借助一个临时变量来实现,这边也借助了这个技巧

根据题意,A,B,C,D点只能存一个包裹,但是A额外配置一个等待队里

在这里插入图片描述
包裹定义

struct Pack {int w = 0; // 快递/快递包的质量bool boxed = false; // 是否打包
};

这里面有歧义的地方

D点位 在已经没有货物过来了,则停止当前的装箱工作,做自检

如何解读这个呢?

  1. 从D点的角度出发,C点没有货物过来
  2. 所有快递都在传输带上了,最后一个新快递刚到A点,激活该策略
  3. 所有快递都在传输带上了,其最后一个快递要么出列,要么重新回到A点,激活该策略

这题,完全没说明这点,而且有case解说,但是没有消除歧义。

目前按2,3去解释,能完全AC,但是两者在特定case下,结果又不一样。


#include <bits/stdc++.h>using namespace std;struct Pack {int w = 0;bool boxed = false; // boxed
};int main() {int n, wmax, w1, w2;cin >> n >> wmax >> w1 >> w2;vector<int> arr(n);for (int &x: arr) cin >> x;int ans1 = 0, ans2 = 0;deque<Pack> A;Pack a, b, c, d;bool ae = false, be = false, ce = false, de = false;auto loop_event = [&](bool flag, int x) -> bool {bool update = false;Pack tmpA;bool tmpAe = false;if (flag) {if (!A.empty()) {Pack top = A.front();if (top.w + x <= wmax) {top.w += x;tmpA = top;tmpAe = true;A.pop_front();} else {tmpA = {x, false}; tmpAe = true;}} else {tmpA = {x, false}; tmpAe = true;}} else {if (!A.empty()) {tmpA = A.front(); A.pop_front();tmpAe = true;}}if (de) {if (ce) {if (!c.boxed && d.w + c.w <= wmax) {d.w += c.w;} else {if (d.w > w2) {ans2++;} else {A.push_back(d);}d = c;d.boxed = true;}ce = false;} else {if (!flag) {// 如果没有新货源,则需要自检并打包/推进,不允许等待if (d.w > w2) {ans2++;update = true;} else {A.push_back(d);}de = false;}}} else {if (ce) {d = c;de = true;d.boxed = true;ce = false;} else {de = false;}}if (be) {if (b.w > w2) {ans1++;update = true;ce = false;} else {c = b;ce = true;}be = false;} else {ce = false;}if (ae) {b = a;be = true;if (b.w > w1) {b.boxed = true;}ae = false;} else {be = false;}a = tmpA;ae = tmpAe;return update;};for (int x: arr) {loop_event(true, x);}int loop = n - ans1 - ans2 + 4;while (loop-- > 0) {if (loop_event(false, -1)) {loop = n - ans1 - ans2 + 4;}}vector<int> left;while (!A.empty()) {left.push_back(A.front().w);A.pop_front();}if (ae) left.push_back(a.w);if (be) left.push_back(b.w);if (ce) left.push_back(c.w);if (de) left.push_back(d.w);sort(left.begin(), left.end());cout << ans1 << " " << ans2 << " " << left.size() << "\n";int mz = left.size();if (mz == 0) cout << "None\n";else {for (int i = 0; i < mz; i++) {cout << left[i] << " \n"[i == mz - 1];}}return 0;
}

期间参考了 小哈里 博客:
2021 RoboCom 世界机器人开发者大赛-本科组(复赛)-T3代码

感觉用四个队列,代码更简洁些,两者另一个差异:规则解读上D点,没有新货物来时, D点的货物该怎么操作。

构造一个特定的case
输入:

5 100 50 80
60 88 88 20 61

输出(按2解释)

2 0 3
20 60 61

输出(按3解释)

2 0 2
61 80

两份代码都能AC,但是特定case输出不一样,睿抗数据还是弱了。

毫无疑问,这是一道好题,但是睿抗的出题,总会整一些歧义点,然后让你拿不了满分,同时使得你陷入到处找茬/猜猜乐的窘境。


7-4 塔防游戏

分值: 30分
思路: dijkstra 板子题

需要逆向从目标点出发,到达僵尸所在地,然后在按时间模拟

注意点:

  • 只要击毁大本营就是胜利,不需要达到大本营地
  • 只要击毁堡垒,才能到达该格子,前后顺序不能相反
  • 当3个僵尸同时攻打某个防御值为2的堡垒,该堡垒消失的同时,3个僵尸都会被扣1滴血 出处参考
  • 每个僵尸军团不能合并,需要维护其独立性
  1. 路径规划
  • 单纯的dijkstra板子即可

时间复杂度为O(n∗m∗log(n∗m))O(n*m*log(n*m))O(nmlog(nm))

  1. 路线模拟
  • 每个军团按单位时间挪动一个位子

时间复杂度为O(T∗2∗(n+m))O(T * 2 * (n + m))O(T2(n+m))


#include <bits/stdc++.h>using namespace std;const int inf = 1e8;struct ST {int w = inf;int s = 0;bool operator<(const ST &o) const {if (w != o.w) return w < o.w;return s < o.s;}
};struct Step {int y, x;ST st;bool operator<(const Step& o) const {return o.st < st;}
};int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int n, m, T;cin >> n >> m >> T;vector<vector<int>> g(n + 2, vector<int>(m + 2));vector<array<int, 3>> js;int ty = -1, tx = -1;for (int i = 0; i <= n + 1; i++) {for (int j = 0; j <= m + 1; j++) {cin >> g[i][j];if (g[i][j] < 0) {ty = i; tx = j;g[i][j] = -g[i][j];} else if ((i == 0 || i == n + 1) && j != 0 && j != m + 1 && g[i][j] > 0) {js.push_back({i, j, g[i][j]});g[i][j] = 0;} else if (i != 0 && i != n + 1 && (j == 0 || j == m + 1) && g[i][j] > 0) {js.push_back({i, j, g[i][j]});g[i][j] = 0;} else if (i == 0 || j == 0 || i == n + 1 || j == m + 1) {g[i][j] = inf;}}}// 逆向dijkstravector<vector<ST>> dp(n + 2, vector<ST>(m + 2));vector<vector<int>> source(n + 2, vector<int>(m + 2, -1));priority_queue<Step, vector<Step>> pq;pq.push({ty, tx, {0, 0}});dp[ty][tx] = {0, 0};int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};while (!pq.empty()) {Step step = pq.top(); pq.pop();int y = step.y, x = step.x;if (dp[y][x] < step.st) continue;for (int i = 0; i < 4; i++) {int ny = y + dirs[i][0];int nx = x + dirs[i][1];if (ny >= 0 && ny <= n + 1 && nx >= 0 && nx <= m + 1) {ST tmp = {dp[y][x].w + g[ny][nx], dp[y][x].s + 1 + g[ny][nx]};if (tmp < dp[ny][nx]) {dp[ny][nx] = tmp;if (ny != 0 && ny != n + 1 && nx != 0 && nx != m + 1) pq.push(Step{ny, nx, tmp});source[ny][nx] = y * (m + 2) + x;}}}}while (T-- > 0) {set<array<int, 2>> hash;vector<array<int, 3>> njs;for (auto &[y, x, w]: js) {int d = source[y][x];int ny = d / (m + 2), nx = d % (m + 2);if (g[ny][nx] > 0) {g[ny][nx]--;hash.insert({ny, nx});if (w > 1) njs.push_back({y, x, w - 1});} else if (hash.count({ny, nx}) != 0) {if (w > 1) njs.push_back({y, x, w - 1});} else {njs.push_back({ny, nx, w});}}if (g[ty][tx] <= 0) break;js.swap(njs);}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (i == ty && j == tx) {cout << min(0, -g[i][j]) << " \n"[j == m];} else {cout << g[i][j] << " \n"[j == m];}}}if (g[ty][tx] <= 0) {cout << "Game Over\n";}return 0;
}

写在最后

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/915659.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《计算机“十万个为什么”》之 MQ

《计算机“十万个为什么”》之 MQ &#x1f4e8; 欢迎来到消息队列的奇妙世界&#xff01; 在这篇文章中&#xff0c;我们将探索 MQ 的奥秘&#xff0c;从基础概念到实际应用&#xff0c;让你彻底搞懂这个分布式系统中不可或缺的重要组件&#xff01;&#x1f680; 作者&#x…

Django母婴商城项目实践(七)- 首页数据业务视图

7、首页数据业务视图 1、介绍 视图(View)是Django的MTV架构模式的V部分,主要负责处理用户请求和生成相应的响应内容,然后在页面或其他类型文档中显示。 也可以理解为视图是MVC架构里面的C部分(控制器),主要处理功能和业务上的逻辑。我们习惯使用视图函数处理HTTP请求,…

android 12 的 aidl for HAL 开发示例

说明&#xff1a;aidl for HAL 这种机制&#xff0c;可以自动生成java代码&#xff0c;app调用可以获取中间过程的jar包&#xff0c;结合反射调用 ServiceManager.getService 方法&#xff0c;直接获取 HAL 服务&#xff0c;不再需要费力在framework层添加代码&#xff0c;方便…

网络安全渗透攻击案例实战:某公司内网为目标的渗透测试全过程

目录一、案例背景二、目标分析&#xff08;信息收集阶段&#xff09;&#x1f310; 外部信息搜集&#x1f9e0; 指纹识别和端口扫描三、攻击流程&#xff08;渗透测试全过程&#xff09;&#x1f3af; 步骤1&#xff1a;Web漏洞利用 —— 泛微OA远程命令执行漏洞&#xff08;CV…

AI视频-剧本篇学习笔记

1.提示词万能框架是什么:ai扮演的角色做什么&#xff1a;解决什么问题怎么做&#xff1a;标准2、剧本模版假设你是一位拥有30年电影拍摄经验的世界顶级导演&#xff0c;拥有丰富的电影拍摄经验和高超的电影拍摄技术&#xff0c;同时也擅长各种影片的剧本创作。我需要你仔细阅读…

A316-HF-DAC-V1:专业USB HiFi音频解码器评估板技术解析

引言 随着高解析度音频的普及&#xff0c;对高品质音频解码设备的需求日益增长。本文将介绍一款专为USB HiFi音频解码器设计的专业评估板——A316-HF-DAC-V1&#xff0c;这是一款基于XMOS XU316技术的高性能音频解码评估平台。产品概述 A316-HF-DAC-V1是一款专业的USB HiFi音频…

超低延迟RTSP播放器在工业机器人远程控制中的应用探索

技术背景 在智能制造高速发展的今天&#xff0c;工业机器人已经从单一的生产作业工具&#xff0c;转变为协作化、智能化的生产伙伴。无论是高精度的多关节机械臂、自主导航的移动机器人&#xff0c;还是与人协同工作的协作机器人&#xff0c;都越来越多地被应用于智能工厂、仓…

Elasticsearch Java 8.x 的聚合 API 及子聚合的用法

背景 Elasticsearch 版本发布的很勤&#xff0c; API 客户端的用法各个版本之间差异也是很大。尤其是 Elasticsearch 8.x 版本直接废弃了 RestHighLevelClient 对象。 Query 和 Aggregation 的 Builder 的用法也有变化。 本文记录项目升级 Elasticsearch API 到 8.x 版本时聚合…

Dify功能熟悉

Dify功能熟悉 文章目录Dify功能熟悉一、介绍1.1 快速开始1.2 官方文档二、workflow2.1 开始和结束2.2 简单示例三、节点3.1 节点一览表3.2 节点-----开始3.3 节点-----LLM3.4 知识检索&#xff08;增强回答准确性&#xff09;3.5 Agent智能体3.6 问题分类器3.7 http四、工具&am…

app引导页设计要点与交互细节详解

在移动应用的设计中&#xff0c;用户第一次打开APP时看到的往往就是app引导页。它不仅是品牌与用户接触的第一道界面&#xff0c;也是决定用户是否愿意继续探索的关键入口。一个设计合理、信息传达清晰的app引导页&#xff0c;能够帮助产品建立专业感与品牌价值&#xff0c;同时…

香港服务器SSH安全加固方案与密钥认证实践

香港服务器SSH安全加固方案与密钥认证实践在数字化时代&#xff0c;服务器安全成为企业不可忽视的重要议题。香港服务器因其地理位置和网络自由优势备受青睐&#xff0c;但同时也面临各种网络安全威胁。本文将深入探讨香港服务器SSH安全加固的核心方案&#xff0c;重点解析密钥…

Python的界面美化库 QDarkStyleSheet

Python的界面美化库 QDarkStyleSheet1、官网先看效果2、github地址3、动态切换主题用法效果代码1、官网先看效果 2、github地址 https://github.com/ColinDuquesnoy/QDarkStyleSheet?tabreadme-ov-file https://qdarkstylesheet.readthedocs.io/en/latest/screenshots.html …

同步本地文件到服务器上的Docker容器

同步本地文件到服务器上的Docker容器 要将本地文件同步到服务器上的Docker容器中&#xff0c;有几种常用方法&#xff1a; 1. 使用 docker cp 命令 # 将本地文件复制到运行中的容器 docker cp /本地/文件/路径 容器名或ID:/容器内/路径# 示例 docker cp ./app.py mycontainer:/…

[学习] 笛卡尔坐标系的任意移动与旋转详解

笛卡尔坐标系的任意移动与旋转详解 文章目录笛卡尔坐标系的任意移动与旋转详解**1. 笛卡尔坐标系基础****2. 坐标变换原理****2.1 平移变换****2.2 旋转变换****3. 组合变换**Python仿真与动态展示**动画说明**&#xff1a;**关键数学原理**&#xff1a;1. 笛卡尔坐标系基础 笛…

论文笔记:Parameter Competition Balancing for Model Merging

neurips 20241 intro近年来&#xff0c;模型融合&#xff08;model merging&#xff09;技术迅速发展&#xff0c;使得可以将多个分别针对不同任务微调后的模型直接集成为一个统一模型&#xff0c;从而实现多任务处理能力&#xff0c;而无需重新访问原始训练数据。然而&#xf…

逆向难度真相:仅用IDA静态分析的极限挑战

逆向难度真相&#xff1a;仅用IDA静态分析的极限挑战 纯IDA逆向难度重排&#xff08;从难到易&#xff09; Python > Go > Java > E语言 > CPython (地狱级难度) IDA困境&#xff1a; 主逻辑完全封装在PYZ/PYC资源中&#xff0c;IDA无法解析字节码结构字符串表只显…

vxe-table 通过配置 ajax 方式自动请求数据,适用于简单场景的列表

vxe-table 通过配置 ajax 方式自动请求数据&#xff0c;适用于简单场景的列表 当系统中很多页面都是简单列表时&#xff0c;每次都要手动去请求接口后再赋值&#xff0c;过程就会比较冗余繁琐。解决方式一般就是将封装一下。本章的方式是通过 vxe-grid 配置 ajax 来实现自动请求…

Zabbix 企业级分布式监控系统深度解析

一、监控系统核心认知1.1 监控的本质与价值监控&#xff08;Monitoring&#xff09;的核心是 “检测与预防”&#xff0c;在 IT 运维中占据约 30% 的权重。其核心价值体现在&#xff1a;风险预判&#xff1a;通过实时监测指标异常&#xff0c;提前发现潜在故障&#xff08;如服…

使用 .NET 6.0 的简单 WebSocket 客户端和服务器应用程序

几个月前&#xff0c;有同事来找我&#xff0c;问能否用 .NET 创建一个简单的 WebSocket 服务器&#xff08;以及之后的客户端&#xff09;。据我了解&#xff0c;他想用它来控制对方电脑上的进程。或许对其他人也有用&#xff0c;所以我把它发布在这里。让我们从服务器开始。我…

【ASP.NET Core】ASP.NET Core中Redis分布式缓存的应用

系列文章目录 链接: 【ASP.NET Core】REST与RESTful详解&#xff0c;从理论到实现 链接: 【ASP.NET Core】深入理解Controller的工作机制 链接: 【ASP.NET Core】内存缓存&#xff08;MemoryCache&#xff09;原理、应用及常见问题解析 文章目录系列文章目录前言一、Redis1.1 …