2021 RoboCom 世界机器人开发者大赛-本科组(初赛)

7-1 懂的都懂

分数 20

作者 DAI, Longao

单位 杭州百腾教育科技有限公司

b3ceb051352ac65c29767cc3ecf2b21192138add.jpg

众所周知,在互联网上有很多话是不好直接说出来的,不过一些模糊的图片仍然能让网友看懂你在说什么。然而对这种言论依然一定要出重拳,所以请你实现一个简单的匹配算法。

现在我们采集了原图的一些特征数据,由 N 个小于 255 的非负整数组成,假设对于给定的若干张由 M**i 个同样小于 255 的非负整数组成的新图的特征数据,每个数据都可以由原图中任意四个不同数据的平均值计算而来,则称新图为原图的相似图片。对于给出的数据,请你判断是不是相似图片。

注意,不同数据指的并非是数据的值不同,而是不能取同一个数据多次。对于两个相同值的数据,如果给出两次,则可以取两次。

输入格式:

输入第一行是两个整数 N,K (1 ≤ N ≤ 50, 1 ≤ K ≤ 200),表示采集的原图的特征数据个数和新图的张数。

接下来一行为 N 个小于 255 的非负整数,表示原图的特征数据。

最后的 K 行,每行第一个数是 M**i (1 ≤ M**i ≤ 200),表示新图的特征数据个数。然后是 M**i 个小于 255 的非负整数,表示新图的特征数据。

输出格式:

对于每一张新图,如果为相似图片,则在一行中输出 Yes,否则输出 No。

输入样例:

5 3
4 8 12 20 40
3 11 16 19
3 12 16 19
10 11 11 11 11 11 11 11 11 11 11

输出样例:

Yes
No
Yes

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

#include <bits/stdc++.h>

using namespace std;

const int N = 1010;

map<int, int> query;

int n, k;
int w[N];

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ ) cin >> w[i];

    for (int a = 1; a <= n; a ++ )
        for (int b = a + 1; b <= n; b ++ )
            for (int c = b + 1; c <= n; c ++ )
                for (int d = c + 1; d <= n; d ++ )
                {
                    int m = w[a] + w[b] + w[c] + w[d];
                    query[m] ++;
                }
    while (k -- )
    {
        int m;
        cin >> m;
        int fl = 0;
        for (int i = 1; i <= m; i ++ )
        {
            int x;
            cin >> x;
            x *= 4;
            if (!query[x]) fl = 1;
        }
        printf ("%s\n", fl ? "No" : "Yes");
        
    }
    return 0;
}

7-2 芬兰木棋

分数 25

作者 DAI, Longao

单位 杭州百腾教育科技有限公司

WX20200212-152528.png

芬兰木棋(Mölkky,又称芬兰木柱)是源自芬兰的一项运动。哲哲将这个运动改造成了赛博朋克单人版,现在场上一开始有 N 根立起的小木棋(上面分别标有一个非负整数),哲哲投掷一根大木棋去击倒这些小木棋以获得分数。分数规则如下:

  • 如果仅击倒 1 根木棋,则得木棋上的分数。
  • 如果击倒 2 根或以上的木棋,则只得击倒根数的分数。(例如击倒 5 根,则得 5 分。)

哲哲固定站在 (0,0) 点上,四周放着若干个小木棋 (X**i,Y**i),坐标均为整数。每次哲哲可以朝一个方向扔出大木棋,大木棋会打倒这个方向上离哲哲最近的 k 个小木棋。哲哲游戏水平很高超,所以这个 k 可以自由控制。

请问哲哲最多能拿多少分,在获得最多分数的情况下最少需要扔出多少次大木棋?

规则与真实规则有较大出入,真实游玩时请以国际莫尔基组织的规则为准

输入格式:

输入第一行是一个正整数 N (1 ≤ N ≤ 105),表示场上一开始有 N 个木棋。

接下来 N 行,每行 3 个整数 X**i,Y**i,P**i,分别表示木棋放置在 (X**i,Y**i),木棋上的分数是 P**i。坐标在 32 位整数范围内,分数为小于等于 1000 的正整数。

保证 (0,0) 点没有木棋,也没有木棋重叠放置。

输出格式:

输出一行两个数,表示最多分数以及获得最多分数最少需要投掷大木棋多少次。

输入样例:

11
1 2 2
2 4 3
3 6 4
-1 2 2
-2 4 3
-3 6 4
-1 -2 1
-2 -4 1
-3 -6 1
-4 -8 2
2 -1 999

输出样例:

1022 9

代码长度限制

16 KB

Java (javac)

时间限制

1800 ms

内存限制

256 MB

Python (python3)

时间限制

800 ms

内存限制

64 MB

Python (python2)

时间限制

800 ms

内存限制

64 MB

其他编译器

时间限制

400 ms

内存限制

64 MB

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<LL, LL > PLL;

LL read()
{
    LL x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch))
    {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x * f;
}

map<PLL,vector<PLL>> query;
LL n;
LL sum, cnt;

int main()
{
    n = read();
    while (n -- )
    {
        LL a = read(), b = read(), c = read();
        sum += c;
        int d = gcd(abs(a), abs(b));
        query[{b / d, a / d}].push_back({a * a + b * b, c});
    }
    for (auto i = query.begin(); i != query.end(); i ++ )
    {
        vector<PLL> v = i->second;
        sort(v.begin(), v.end());
        for (int j = 0; j < v.size(); j ++ )
        {
            if (v[j].second != 1) cnt ++;
            else
            {
                if (v[j].second != v[j + 1].second && j < v.size()) cnt ++;
            }
        }
    }
    printf ("%lld %lld\n", sum, cnt);
    
    return 0;
}

7-3 打怪升级

分数 25

作者 陈越

单位 浙江大学

dgsj.JPG

很多游戏都有打怪升级的环节,玩家需要打败一系列怪兽去赢取成就和徽章。这里我们考虑一种简单的打怪升级游戏,游戏规则是,给定有 N 个堡垒的地图,堡垒之间有道路相连,每条道路上有一只怪兽把守。怪兽本身有能量,手里的武器有价值。打败怪兽需要的能量等于怪兽本身的能量,而怪兽一旦被打败,武器就归玩家所有 —— 当然缴获的武器价值越高,玩家就越开心。

你的任务有两件:

    1. 帮助玩家确定一个最合算的空降位置,即空降到地图中的某个堡垒,使得玩家从这个空降点出发,到攻下最难攻克(即耗费能量最多)的那个堡垒所需要的能量最小;
    1. 从这个空降点出发,帮助玩家找到攻克任意一个其想要攻克的堡垒的最省能量的路径。如果这种路径不唯一,则选择沿途缴获武器总价值最高的解,题目保证这种解是唯一的。

输入格式:

输入第一行给出两个正整数 N (≤1000) 和 M,其中 N 是堡垒总数,M 是怪兽总数。为简单起见,我们将堡垒从 1 到 N 编号。随后 M 行,第 i 行给出了第 i 只怪兽的信息,格式如下:

B1 B2 怪兽能量 武器价值

其中 B1B2 是怪兽把守的道路两端的堡垒编号。题目保证每对堡垒之间只有一只怪兽把守,并且 怪兽能量武器价值 都是不超过 100 的正整数。

再后面是一个正整数 K(≤N)和玩家想要攻克的 K 个目标堡垒的编号。

输出格式:

首先在一行中输出玩家空降的堡垒编号 B0。如果有多种可能,则输出编号最小的那个。

随后依次为玩家想要攻克的每个堡垒 B 推荐最省能量的攻克路径,并列出需要耗费的能量值和沿途缴获武器的总价值。注意如果最省力的路径不唯一,则选择沿途缴获武器总价值最高的解。格式为:

B0->途经堡垒1->...->B
总耗费能量 武器总价值

输入样例:

6 12
1 2 10 5
2 3 16 20
3 1 4 2
2 4 20 22
4 5 2 2
5 3 12 6
4 6 8 5
6 5 10 5
6 1 20 25
1 5 8 5
2 5 2 1
2 6 8 5
4
2 3 6 5

输出样例:

5
5->2
2 1
5->1->3
12 7
5->4->6
10 7
5
0 0

代码长度限制

16 KB

时间限制

5000 ms

内存限制

64 MB

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

using namespace std;
const int N = 1010;

bool st[N];
int n, m, dist[N];
int dis[N], res[N], pre[N];
int S[N][N], D[N][N];

int dijkstra(int f)
{
	memset(st, 0, sizeof st);
	memset(dis, 0x3f, sizeof dis);
	memset(res, 0, sizeof res);
	
	dis[f] = 0;
	while(true)
	{
		int t = -1;
		for(int i = 1; i <= n; i++)
			if(!st[i] && (t == -1 || dis[t] > dis[i]))
				t = i;
		
		if(t == -1)
			break;
		st[t] = true;
		
		for(int i = 1; i <= n; i++)
		{
			if(dis[i] > dis[t] + S[t][i])
			{
				pre[i] = t;
				dis[i] = dis[t] + S[t][i];
				res[i] = res[t] + D[t][i];
			}
			else if(dis[i] == dis[t] + S[t][i])
			{
				if(res[i] < res[t] + D[t][i])
				{
					pre[i] = t;
					res[i] = res[t] + D[t][i];
				}
			}
		}
	}
	
	int ans = 0;
	for(int i = 1; i <= n; i++) ans = max(ans, dis[i]);
	return ans;
}

void dfs(int x, int id)
{
	if(x == id)
		return ;
	dfs(pre[x], id);
	printf("->%d", x);
}

int main()
{
	memset(S, 0x3f, sizeof S);

    n = read(), m = read();
	while(m--)
	{
        int a = read(), b = read(), s = read(), d = read();
		S[a][b] = S[b][a] = min(S[a][b], s);
		D[a][b] = D[b][a] = max(D[a][b], d);
	}
	
	for(int i = 1; i <= n; i++)
		dist[i] = dijkstra(i);
	
	int id = 1;
	for(int i = 1; i <= n; i++)
		if(dist[id] > dist[i])
			id = i;
	
	printf("%d\n", id);
	dijkstra(id);
	
	int k, x;
	scanf("%d", &k);
	while(k--)
	{
		scanf("%d", &x);
		printf("%d", id);
		dfs(x, id);
		printf("\n");
		printf("%d %d\n", dis[x], res[x]); 
	}
	return 0;
}

, d = read();
S[a][b] = S[b][a] = min(S[a][b], s);
D[a][b] = D[b][a] = max(D[a][b], d);
}

for(int i = 1; i <= n; i++)
	dist[i] = dijkstra(i);

int id = 1;
for(int i = 1; i <= n; i++)
	if(dist[id] > dist[i])
		id = i;

printf("%d\n", id);
dijkstra(id);

int k, x;
scanf("%d", &k);
while(k--)
{
	scanf("%d", &x);
	printf("%d", id);
	dfs(x, id);
	printf("\n");
	printf("%d %d\n", dis[x], res[x]); 
}
return 0;

}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星辰予曦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值