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

7-1 懂的都懂  (分数 20)

b3ceb051352ac65c29767cc3ecf2b21192138add.jpg

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

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

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

输入格式:

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

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

最后的 K 行,每行第一个数是 Mi​ (1 ≤ Mi​ ≤ 200),表示新图的特征数据个数。然后是 Mi​ 个小于 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

解析:

        遍历原序列,统计出所有任意四个不同数的和。

        对于测试数据的每一个数 x ,查看是否存在 x*4

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,a[N],k,x,y;
set<int>s;
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			for(int k=j+1;k<=n;k++)
				for(int u=k+1;u<=n;u++) s.insert(a[i]+a[j]+a[k]+a[u]);
	for(int i=0;i<k;i++){
		int f=1;
		cin>>x;
		for(int j=0;j<x;j++){
			cin>>y;
			if(s.count(y*4)==0) f=0;
		}
		if(f) puts("Yes");
		else puts("No");
	}
	return 0;
}

        


7-2 芬兰木棋  (分数 25)

WX20200212-152528.png

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

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

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

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

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

输入格式:

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

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

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

输出格式:

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

输入样例:

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

解析:

        显然最大分数即为所有分数之和。

        将棋子按照 {x,y} 进行分类,并且记录距离和分数。

        对于每一列上的所有棋子,按照距离进行排序。分数大于1则每次击倒一个,否则击倒连续的1分数的棋子即为最少击倒次数。

        开long long

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,sum;
map<pair<ll,ll>,vector<pair<ll,ll>>>mp;
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		ll x,y,p;
		scanf("%lld%lld%lld",&x,&y,&p);
		int t=abs(__gcd(x,y));
		mp[{x/t,y/t}].push_back({x*x+y*y,p});
		sum+=p;
	}
	ll cnt=0;
	for(auto it:mp){
		vector<pair<ll,ll>>v=it.second;
		sort(v.begin(),v.end());
		for(int i=0;i<v.size();i++){
			if(v[i].second!=1) cnt++;
			else if(i+1==v.size()||v[i+1].second!=1) cnt++;
		}
	}
	printf("%d %d",sum,cnt);
	return 0;
}

7-3 打怪升级   (分数 25)

dgsj.JPG

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

你的任务有两件:

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

输入格式:

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

B1 B2 怪兽能量 武器价值

其中 B1 和 B2 是怪兽把守的道路两端的堡垒编号。题目保证每对堡垒之间只有一只怪兽把守,并且 怪兽能量 和 武器价值 都是不超过 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

解析:

        对于所有点各跑一遍Dijkstra,找出起点start

        再从起点跑一边Dijkstra得出到各点耗费的能量、获得的武器、路径

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010,INF=0x3f3f3f3f;
int n,m,k,x,pre[N],start;
int dis[N],done[N],sum[N];
void print(int s,int t){
	if(s==t){
		printf("%d",s);
		return;
	}
	print(s,pre[t]);
	printf("->%d",t);
}
struct edge{
	int to,v,w;
};
vector<edge>e[N];
struct node{
	int id,dis;
	bool operator<(const node& a)const{
		return dis>a.dis;
	}
};
int Dijkstra(int s){
	int dis[N],done[N];
	for(int i=1;i<=n;i++) dis[i]=INF,done[i]=0;
	priority_queue<node>q;
	q.push({s,0});
	dis[s]=0;
	while(q.size()){
		node u=q.top();
		q.pop();
		if(done[u.id]) continue;
		done[u.id]=1;
		for(int i=0;i<e[u.id].size();i++){
			edge x=e[u.id][i];
			if(done[x.to]) continue;
			if(dis[x.to]>dis[u.id]+x.v){
				dis[x.to]=dis[u.id]+x.v;
				q.push({x.to,dis[x.to]});
			}
		}
	}
	int mx=0;
	for(int i=1;i<=n;i++) mx=max(mx,dis[i]);
	return mx;
}
void solve(){
	for(int i=1;i<=n;i++) dis[i]=INF,done[i]=0,sum[i]=0;
	priority_queue<node>q;
	q.push({start,0});
	dis[start]=0;
	while(q.size()){
		node u=q.top();
		q.pop();
		if(done[u.id]) continue;
		done[u.id]=1;
		for(int i=0;i<e[u.id].size();i++){
			edge x=e[u.id][i];
			if(done[x.to]) continue;
			if(dis[x.to]>dis[u.id]+x.v){
				dis[x.to]=dis[u.id]+x.v;
				sum[x.to]=sum[u.id]+x.w;
				q.push({x.to,dis[x.to]});
				pre[x.to]=u.id;
			}
			else if(dis[x.to]==dis[u.id]+x.v){
				if(sum[u.id]+x.w>sum[x.to]){
					sum[x.to]=sum[u.id]+x.w;
					pre[x.to]=u.id;
				}
			}
		}
	}	
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int a,b,c,d;
		scanf("%d%d%d%d",&a,&b,&c,&d);
		e[a].push_back({b,c,d});
		e[b].push_back({a,c,d});
	}
	int minn=INF;
	for(int i=1;i<=n;i++){
		int t=Dijkstra(i);
		if(t<minn) start=i,minn=t;
	}
	cout<<start<<"\n";
	scanf("%d",&k);
	solve();
	for(int i=0;i<k;i++){
		scanf("%d",&x);
		print(start,x);
		printf("\n%d %d\n",dis[x],sum[x]);
	}
	return 0;
}

7-4 疫情防控  (分数 30)

疫情尚未结束,严防疫情反复。为了做好疫情防控工作,国内设置了地区风险等级,对于中高风险地区的人员采取限制移动、居家隔离等手段。

为了研究疫情防控对于跨地区交通运输的影响,假设现在有 N 个机场,M 条航线,每天都会新增一个防控地区,一个防控地区会导致一个机场无法正常运作,航线也自然无法正常运行,每天会有 Qi​ 对旅客从 Xi​ 机场前往 Yi​ 机场,请计算有多少对旅客会受到影响无法完成行程。

旅客只要能直达或通过若干次中转,且乘坐的所有航线的出发和到达机场都正常运作,即视作可完成行程。

输入格式:e

输入第一行是三个整数 N,M,D (1≤N≤5×1e4, 1≤M≤2×1e5, 1≤D≤1e3), 表示机场数、航线数以及新增防控地区的天数。

接下来首先有 M 行,每行给出空格分隔的两个数字 A 和 B,表示编号为 A 和 B 的机场之间有一条航线。航线是双向的,机场编号从 1 到 N。e

然后是 D 块输入,每块输入内第一行为空格分隔的两个整数 C 和 Q (1≤Q≤1e3),表示新增机场编号为 C 所在的城市为防控地区,今天有 Q 段行程。数据保证新增的城市之前一定不是防控地区。

接下来的 Q 行,每行是空格分隔的两个数字 X 和 Y,表示编号为 X 和 Y 的机场的一段行程。行程有可能包括之前就已经成为防控地区的城市。

输出格式:

对于每天的询问,请在一行中输出在新增了一个防控地区后当天的行程有多少不能成行。

输入样例:

5 5 3
1 2
1 3
1 5
2 5
3 4
4 3
1 3
1 4
2 3
5 3
3 4
2 3
3 5
1 3
2 3
2 5
3 4

输出样例:

1
2
3

解析:

        并查集,但是并查集不能删除关系。

        记录所有边、每次删除的点、每次查询的航线。

        然后对于没有删除的点全部并查集建图。

        然后从最后一天往前遍历,每次在当前的图中查询当前的查询数据,统计不联通的数量。然后将当前一天删除的点和其相连的边加入并查集。

        这样反向建图可以实现并查集“删除”的操作。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
int n,m,d;
int c[N],q[N];
int p[N];
set<int>s;
vector<int>e[N];
map<int,vector<pair<int,int>>>mp;
int find(int x){
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
int main(){
	scanf("%d%d%d",&n,&m,&d);
	for(int i=1;i<=m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		e[a].push_back(b);
		e[b].push_back(a);
	}
	for(int i=1;i<=d;i++){
		scanf("%d%d",&c[i],&q[i]);
		s.insert(c[i]);
		for(int j=0;j<q[i];j++){
			int a,b;
			scanf("%d%d",&a,&b);
			mp[i].push_back({a,b});
		}
	}
	for(int i=1;i<=n;i++) p[i]=i;
	for(int i=1;i<=n;i++){
		if(s.count(i)) continue;
		for(int j=0;j<e[i].size();j++){
			int to=e[i][j];
			if(s.count(to)==0){
				int a=find(i);
				int b=find(to);
				if(a!=b) p[b]=a;
			} 
		}
	}
	int res[N];
	for(int i=d;i>0;i--){
		vector<pair<int,int>>v=mp[i];
		for(int j=0;j<v.size();j++){
			int a=find(v[j].first);
			int b=find(v[j].second);
			if(a!=b) res[i]++;
		}
		int r=c[i];
		for(int j=0;j<e[r].size();j++){
			if(s.count(e[r][j])) continue;
			int a=find(e[r][j]);
			int b=find(r);
			if(a!=b) p[a]=b;
		}
		s.erase(c[i]);
	}
	for(int i=1;i<=d;i++) printf("%d\n",res[i]);
	return 0;
}

机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码 机器人大赛作品,供参人员参考,含设计文档,设计源码
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值