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

看群友在水这个比赛玩玩,于是也去打了一下重现赛。
事实证明,群友轻松AK,而我只会暴力。
总的难度就是PAT甲的难度吧,数据很不错,恶心的一批。
补题完结

2021RoboCom机器人开发者大赛官方题解

7-1 懂的都懂 (20 分)【简单 / 暴力 + 哈希表】

方法一: 自己的傻叉做法 预处理所有的4个数的平均值。用double 注意精度

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
double a[N],b[N];
map<double,int>mp;
int main(void)
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%lf",&a[i]);
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			for(int k=j+1;k<n;k++)
			{
				for(int z=k+1;z<n;z++)
				{
					int temp=a[i]+a[j]+a[k]+a[z];
					mp[temp/4.0]++;
				}
			}
		}
	}
	while(m--)
	{
		int t; scanf("%d",&t);
		bool flag=1;
		for(int i=0;i<t;i++) 
		{
			scanf("%lf",&b[i]);
			if(!mp[b[i]]) flag=false;
		}
		if(flag) puts("Yes");
		else puts("No");
	}
	return 0;
}

方法二: 只需处理所有的四个数的和即可,不用求平均

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int a[N],b[N];
map<int,int>mp;
int main(void)
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			for(int k=j+1;k<n;k++)
			{
				for(int z=k+1;z<n;z++)
				{
					int temp=a[i]+a[j]+a[k]+a[z];
					mp[temp]++;
				}
			}
		}
	}
	while(m--)
	{
		int t; scanf("%d",&t);
		bool flag=1;
		for(int i=0;i<t;i++) 
		{
			scanf("%d",&b[i]);
			if(!mp[b[i]*4]) flag=false;
		}
		if(flag) puts("Yes");
		else puts("No");
	}
	return 0;
}

7-2 芬兰木棋 (25 分)【中 / map 贪心】

大木棋会打倒这个方向上离哲哲最近的 k 个小木棋
读了半天的假题。

1 1 1
2 2 2
3 3 1
步数为3 先打123
#include<bits/stdc++.h>
using namespace std;
typedef long long  LL;
LL ans,n,cnt;
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
map<pair<LL,LL>,vector< pair<LL,LL> > >mp;//斜率映射到对应的距离加分数
int main(void)
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		LL x,y,c; cin>>x>>y>>c;
		ans+=c;
		LL temp=gcd(abs(x),abs(y));
		mp[{x/temp,y/temp}].push_back({x*x+y*y,c}); //注意: 距离必须是x*x+y*y 单独的x是不行的因为还有y轴上的点
	}
    cnt=0;
	for(auto i=mp.begin();i!=mp.end();i++)//枚举所有的方向
	{
		auto ve=i->second;
		sort(ve.begin(),ve.end());//距离排序
		for(int j=0;j<ve.size();j++)
		{
			if(ve[j].second!=1) 
			{
				cnt++;
				if(j-1>=0&&ve[j-1].second==1) cnt++;
			}
		}
		if(ve[ve.size()-1].second==1) cnt++;
	}
	cout<<ans<<" "<<cnt;
	return 0;
}

7-3 打怪升级 (25 分) 【中 / 最短路 记得维护值 和 存路径】

写的可以过,不过有点太卡时间。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,m,t,x;
int g[N][N],dist[N],st[N];
int startx,maxv=1e9;
int p[N][N];
map<int,int>val,ans;//val存的是该点最大的价值,ans存路径 
void Dijkstra(int x)
{
	memset(dist,0x3f,sizeof dist);
	memset(st,0,sizeof st);
	dist[x]=0;
	for(int i=0;i<n;i++)
	{
		int t=-1;
		for(int j=1;j<=n;j++) if(!st[j]&&(t==-1 || dist[j]<dist[t] )) t=j;
		st[t]=1;
		for(int j=1;j<=n;j++)
		{
			if(dist[j]>dist[t]+g[t][j])
			{
				dist[j]=dist[t]+g[t][j];
				val[j]=val[t]+p[t][j];
				ans[j]=t;
			}
			else if(dist[j]==dist[t]+g[t][j])
			{
				if(val[j]<val[t]+p[t][j])
				{
					val[j]=val[t]+p[t][j];
					ans[j]=t;
				}
			}
		}
	}
	int temp=0;
	for(int i=1;i<=n;i++) temp=max(temp,dist[i]);
	if(temp<maxv) maxv=temp,startx=x;
}
int main(void)
{
	memset(g,0x3f,sizeof g);
	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);
		g[a][b]=g[b][a]=c;
		p[a][b]=d,p[b][a]=d;
	}
	for(int i=1;i<=n;i++) Dijkstra(i);//每一个点跑一下最短路,找到最短路中最大的值,最小的值
	printf("%d\n",startx);
	val.clear(),ans.clear();
	Dijkstra(startx);
	scanf("%d",&t);
	while(t--)
	{
		int x; scanf("%d",&x);
		int node=x;
		vector<int>path;
		while(node)
		{
			path.push_back(node);
			node=ans[node];
		}
		for(int i=path.size()-1;i>=0;i--) 
		{
			if(i!=path.size()-1) printf("->");
			printf("%d",path[i]);
		}
		printf("\n%d %d\n",dist[x],val[x]);
	}
	return 0;
}

7-4 疫情防控 (30 分)【难度: 难 / 并查集 思维】

很轻松的暴力做法骗22分

#include<bits/stdc++.h> 
using namespace std;
const int N=1e5*3+10;
int h[N],e[N],ne[N],idx;
int st[N],vis[N];
int n,m,t;
int startx,endx;
bool flag;
void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
void dfs(int u)
{
	st[u]=1;
	if(u==endx&&!vis[u]) 
	{
		flag=1;
		return;
	}
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(!st[j]&&!vis[j]) dfs(j);
	}
}
int main(void)
{
	memset(h,-1,sizeof h);
	cin>>n>>m>>t;
	for(int i=0;i<m;i++)
	{
		int a,b; cin>>a>>b;
		add(a,b),add(b,a);
	}
	while(t--)
	{
		int c,q; cin>>c>>q;
		vis[c]=1;
		int ans=q;
		for(int i=0;i<q;i++)
		{
			memset(st,0,sizeof st);
			flag=0;
			cin>>startx>>endx;
			if(!vis[startx])dfs(startx);
			if(flag) ans--;
		}
		cout<<ans<<endl;
	}
	return 0;
}

正解: 考虑将所有操作离线,逆序处理。即,先删除要删除的所有点,再倒着往里加点,顺便把询问处理掉,用并查集维护即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef pair<int,int> PII;
vector<int>ve[N];//存边 
vector<PII>vis[N];
int p[N],s[N],ans[N];
int n,m,t;
int find(int x) 
{
	if(x!=p[x]) p[x]=find(p[x]);
	return p[x];
}
int main(void)
{
	cin>>n>>m>>t;
	for(int i=1;i<=n;i++) p[i]=i;
	for(int i=1;i<=m;i++)
	{
		int a,b; cin>>a>>b;
		ve[a].push_back(b) ;
		ve[b].push_back(a);
	}
	for(int i=1;i<=t;i++)
	{
		int k,a,b; 
		cin>>s[i]>>k;
		p[s[i]]=0;//标记为坏的 
		while(k--)
		{
			cin>>a>>b;
			vis[i].push_back({a,b});
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(p[i])
		{
			for(int j=0;j<ve[i].size();j++)
			{
				if(p[ve[i][j]]) p[find(i)]=find(ve[i][j]);
			}
		}
	}
	for(int i=t;i;i--)
	{
		for(int j=0;j<vis[i].size();j++)//查询
		{
			int fa=find(vis[i][j].first);
			int fb=find(vis[i][j].second);
			if(fa!=fb || fa==0 ) ans[i]++;
		}
		int k=s[i]; p[k]=k;//添加点
		for(int j=0;j<ve[k].size();j++)//并查集处理
		{
			if(p[ve[k][j]]) p[find(k)]=find(ve[k][j]);
		}
	}
	for(int i=1;i<=t;i++) cout<<ans[i]<<endl;
	return 0;
}
  • 24
    点赞
  • 111
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码 机器人大赛参赛作品,供参赛人员参考,含设计文档,设计源码
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值