2021 RoboCom 世界机器人开发者大赛-本科组(复赛)
Posted 小哈里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021 RoboCom 世界机器人开发者大赛-本科组(复赛)相关的知识,希望对你有一定的参考价值。
文章目录
7-1 冒险者分队 20
7-1 冒险者分队
分数 20
作者 DAI, Longao
单位 杭州百腾教育科技有限公司
冒险者分队是人气 MMORPG《最终幻想 14》里的一个游戏系统。玩家通过招募 NPC (非玩家角色)组成小队完成特定任务后可以获取丰厚的奖励。
由于完成任务有能力的要求,因此我们需要对 NPC 进行一定的训练。NPC 组成的小队会有三个属性:体能、心智,以及战术,玩家可以选择以下的两种训练课程之一对小队进行训练:
提升其中一个属性 40,降低其他两个属性各 20;
提升其中两个属性 20,降低剩下一个属性 40。
如果在选择的训练课程后有任意一个属性小于 0,那么训练会失败,属性不会发生变化。
为了完成特定任务,现在给定小队的初始属性和目标属性,请回答是否有可能通过一定的训练,使得小队的属性正好达到目标属性的值,如果可以的话,最少的次数是多少?
输入格式:
输入第一行是一个正整数 T (≤10
5
),表示有多少组询问。
接下来的 T 组询问,每组询问有两行,每行三个非负整数,第一行为小队初始的属性,第二行为需要达成的目标属性。
所有属性值均大于等于 0,小于等于 2×10
9
。
输出格式:
如果目标属性无法通过训练达到,输出一行 −1,否则输出一个整数,表示达到目标属性的最少训练次数。
输入样例:
4
25 30 35
65 10 15
100 200 300
200 180 220
100 100 100
0 0 0
777 888 999
777 888 999
输出样例:
1
3
-1
0
- 题意:给出初始数组和目标数组,长都为3。每次可以给两个数+20,一个-40,或者两个-20,一个加40,求最少多少次能变成目标数组。
- 思路:
- 首先,初始数组和目标数组之间只能通过20来变换,所以对应位置的值作差%20,有余数肯定直接-1。然后把三个差值/20,简化问题。
- 然后,考虑非法的情况,不管是-1,-1,+ 2还是 -2,+1,+1,这三个数%3的值都是1,因为最后要让差值从(a,b,c)变成(0,0,0),所以原本的这三个差值必须%3相等,否则-1。
- 最后,考虑构造最优解。 设a < b < 0 < c,我们以1,1,-2作用于三者,那么b会首先变成0。再然后,再以两个操作2,-1,-1和1,1,-2组合成3,0,-3作用于a和c,就可以构造出(0,0,0)。(如果a或c不能被3整除怎么办?事实是不会的,因为上面已经判过三者对3同余了,所以三者%3都等于0,必定是能整除的)
#include<bits/stdc++.h>
using namespace std;
int a[10], b[10], c[10];
int main()
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; cin>>T;
while(T--)
for(int i = 1; i <= 3; i++)cin>>a[i];
//-1
int ok = 1;
for(int i = 1; i <= 3; i++)
cin>>b[i]; c[i] = b[i]-a[i];
if(c[i]%20!=0)ok = 0;
c[i] /= 20;
if(a[1]+a[2]+a[3] != b[1]+b[2]+b[3])ok = 0;
int mod = (c[1]%3+3)%3;
for(int i = 2; i <= 3; i++)
if((c[i]%3+3)%3 != mod)ok = 0;
if(ok==0) cout<<"-1\\n"; continue;
//构造
int num = 0;
num += (c[1]>0)+(c[2]>0)+(c[3]>0);
if(num==2)c[1]=-c[1], c[2]=-c[2], c[3]=-c[3];
int x = min(c[1],c[2],c[3]), z = max(c[1],c[2],c[3]), y = c[1]+c[2]+c[3]-x-z;//排序
int res = 0;
res += -y; x -= y; z += y*2; y = 0; //操作1
res += z/3*2; //操作2
cout<<res<<"\\n";
return 0;
7-2 拼题A打卡奖励 25
7-2 拼题A打卡奖励
分数 25
作者 陈越
单位 浙江大学
拼题 A 的教超搞打卡活动,指定了 N 张打卡卷,第 i 张打卡卷需要 m
i
分钟做完,完成后可获得 c
i
枚奖励的金币。活动规定每张打卡卷最多只能做一次,并且不允许提前交卷。活动总时长为 M 分钟。请你算出最多可以赢得多少枚金币?
输入格式:
输入首先在第一行中给出两个正整数 N(≤10
3
) 和 M(≤365×24×60),分别对应打卡卷的数量和以“分钟”为单位的活动总时长(不超过一年)。随后一行给出 N 张打卡卷要花费的时间 m
i
(≤600),最后一行给出 N 张打卡卷对应的奖励金币数量 c
i
(≤30)。上述均为正整数,一行内的数字以空格分隔。
输出格式:
在一行中输出最多可以赢得的金币数量。
输入样例:
5 110
70 10 20 50 60
28 1 6 18 22
输出样例:
40
样例解释:
选择最后两张卷子,可以在 50+60=110 分钟内获得 18+22=40 枚金币。
- 题意:n个物品,有价值和体积,每个可以选一次,背包容量m,求最大价值。
- 思路:
- 01背包板子题???果然TLE(15分)。
n < 1e3, m < 5e5,所以O(nm)1e8肯定会超时。 - 发现金币数量ci < 30 成为一个突破口,此时所有物品总价值不超过1000∗30,因此可以转换原本的求 “最小容量(5e5)下的最大价值” 为 “最大价值(3e4)下的最小容量”,系数都是n,3e7勉强可以通过。
- 01背包板子题???果然TLE(15分)。
//15分
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int v[maxn], w[maxn];
int f[maxn*maxn];
int main()
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n, m; cin>>n>>m;
for(int i = 1; i <= n; i++)cin>>v[i];
for(int i = 1; i <= n; i++)cin>>w[i];
for(int i = 1; i <= n; i++)
for(int j = m; j >= 0; j--)
if(j>=v[i])f[j] = max(f[j], f[j-v[i]]+w[i]);
cout<<f[m]<<"\\n";
return 0;
//25分
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int v[maxn], w[maxn];
int f[maxn*maxn];
int main()
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n, m; cin>>n>>m;
int sum = 0;
for(int i = 1; i <= n; i++)cin>>v[i];
for(int i = 1; i <= n; i++)cin>>w[i], sum += w[i];
memset(f,0x3f,sizeof(f));
f[0] = 0;
for(int i = 1; i <= n; i++)
for(int j = sum; j >= w[i]; j--)
f[j] = min(f[j], f[j-w[i]]+v[i]);
for(int i = sum; i >= 0; i--)
if(f[i]<=m)
cout<<i; return 0;
return 0;
7-3 快递装箱 25
7-3 快递装箱
分数 25
作者 陈越
单位 浙江大学
bt.png
有一条快递装箱的流水线是这样设计的(见下图):
fig.png
快递件从 A 口进入流水线转盘;到达 B 时进行称重,如果重量大于 W
1
就开一个新的箱子把它装进去,否则直接让它通过;到达C时检查箱子的重量,如果超过了 W
2
(>W
1
),就直接装车 —— 这条线有 1 号摄像头拍摄装车的箱子编号并记录;重量不达标的箱子或快递件继续行进到 D,在这里进行装箱处理。这里分几种情况:
如果 D 当前是空的,那么新开一箱给到达的快递件,或者如果到达的是一只箱子,那么等待下一个快递件到达;
如果 D 当前不是空的,那么肯定是有一只箱子。这时考察下一个物体 —— 如果下一个是快递件并且能装入这个箱子(即总重量不超过箱子的最大容量 W
max
),则将其装入;如果下一个是快递件但装不下了(这时新的快递件装箱),或者下一个来的就是箱子,或者已经没有货物过来了,则停止当前的装箱工作,检查当前这个箱子的重量,超过 W
2
就装车 —— 这条线有 2 号摄像头拍摄装车的箱子编号并记录;如果重量不足,则继续前进到 A 口,与新到的快递件汇合。D 点继续处理下一个排队的箱子或快递件。
而到 A 口的箱子则要看汇合的快递件能否装入:如果可以就装箱,向 B 进发;不行就一直等待,直到下一个可以装箱的快递装进去,或者没有任何新的快递到达,才继续向 B 进发。当有多只箱子从 D 转过来时,按到达的顺序排队。
简单起见,我们假设快递件匀速进入流水线,所有快递件从一个点到下一个点都只需要一个单位时间,并且在 B 和 C 的停留时间可忽略不计。当 B 发现重量大于 W
1
的是已经在箱子里的货物时,则不必再新开一个箱子。
输入格式:
输入在第一行给出 4 个正整数:N 为快递件的数量;W
max
、W
1
和 W
2
,如题面所述。其中 N≤10
4
,W
1
<W
2
<W
max
≤10
3
。
随后一行给出 N 个不超过 W
max
的正整数,为顺序到达的快递件的重量。
输出格式:
在第一行中先后输出第 1、2 号摄像头拍摄的装车箱子的数量、以及最后转盘上剩下的箱子的数量。第二行按非递减序输出剩下的箱子的重量。如果没有箱子剩下,则输出 None。
同一行数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
11 100 50 80
85 25 60 21 10 52 80 95 78 15 3
输出样例:
2 1 4
40 55 78 80
样例说明:
我们按照“单位时间:事件”的格式描述整个过程。
时间 A B C D
1 85 - - -
2 25 85装箱 - -
3 60 25 85装车,1号拍摄 -
4 21 60装箱 25 -
5 10 21 60一箱 25装箱
6 52 10 21 60一箱到,25一箱启动
7 80不能装箱,25一箱等待 52装箱 10 21装箱得到81一箱
8 95不能装箱,25一箱等待 80装箱 52一箱 10装箱得到91一箱
9 78不能装箱,25一箱等待 95装箱 80一箱 52一箱到,91一箱装车,2号拍摄
10 15装箱得到40一箱 78装箱 95一箱装车,1号拍摄 80一箱到,52一箱启动
11 3装箱得到55一箱 40一箱 78一箱 80一箱
此时摄像头 1 拍摄了 2 次,摄像头 2 拍摄了 1 次,转盘上还剩 4 只重量为 55、40、78 和 80 的箱子。
- 题意:模拟流水线,塞个货物进传送带,然后往后运动,更新一下每个点的状态,如果有货物运出就答案加一,照着题目意思做就行。
- 思路:
A、D 点用双端队列处理(因为有塞回去的情况),B、C用普通队列处理。
用一个 pair 存储货物状态,分别记录重量和是否装箱,每次按题目要求更新即可。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int maxn = 1010;
int n, wmax, w1, w2;
vector<int>ans;
int ans1, ans2;
deque<PII>A, D;
queue<PII>B, C;
void update() //每次按DCBA的顺序处理一遍当前流水线上的箱子
if(D.size()!=0)
PII x = D.front();
if(x.second == 0) //x没装箱,给x装箱
D.pop_front();
D.push_front(make_pair(x.first,1));
else
D.pop_front();
if(D.size()==0)D.push_front(x);//x不是最后一个就纳入出队考核
else
PII y = D.front();
if(y.second == 0)//y没装箱
if(y.first+x.first <= wmax)//给y+x装箱
D.pop_front();
D.push_front(make_pair(x.first+y.first, 1));
else
if(x.first>w2)ans2++; //x正式出队
else A.push_back(x); //给x放回去A重生
else
if(x.first > w2)ans2++; //x正式出队
else A.push_back(x); //给x放回去A重生
if(D.front().second == 0) //z没装箱,给z装箱
PII z = D.front(); D.pop_front();
D.push_front(make_pair(z.first,1));
if(C.size()!=0)
PII x = C.front(); C.pop();
if(x.first > w2)ans1++;
else D.push_back(x);
if(B.size()!=0)
PII x = B.front(); B.pop();
if(x.first > w1)C.push(make_pair(x.first, 1));
else C.push(x);
if(A.size()!=0)
B.push(A.front()); A.pop_front();
int main()
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>wmax>>w1>>w2;
for(int i = 1; i <= n; i++)
int x; cin>>x; //把x放到A口,考虑是否装箱
if(A.size()==0)A.push_back(make_pair(x,0));
else
PII y = A.front();
if(y.first + x <= wmax)
A.pop_front();
A.push_front(make_pair(y.first+x, 1));
else
A.push_front(make_pair(x,0));
update(); //更新一下
//solve
for(int i = 1; i <= 10050; i++)update();//让流水线转很多轮
queue<PII>D2; //临时队列
while(D.size() != 0)
PII x = D.front(); D.pop_front();
if(x.first > w2)ans2++; else D2.push(x);
while(D2.size()!=0) D.push_back(D2.front()); D2.pop();
while(A.size()!=0)if(A.front().first != 0)ans.push_back(A.front().first); A.pop_front();
while(B.size()!=0)if(B.front().first != 0)ans.push_back(B.front().first); B.pop();
while(C.size()!=0)if(C.front().first != 0)ans.push_back(C.front().以上是关于2021 RoboCom 世界机器人开发者大赛-本科组(复赛)的主要内容,如果未能解决你的问题,请参考以下文章
2021 RoboCom 世界机器人开发者大赛-本科组(初赛)完结
2021 RoboCom 世界机器人开发者大赛-本科组(复赛)
2021 RoboCom 世界机器人开发者大赛-本科组(复赛)
2021 RoboCom 世界机器人开发者大赛-本科组(决赛)