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

160 阅读3分钟

7-1绿色围栏(模拟)

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目链接:PTA | 程序设计类实验辅助教学平台

image.png

样例输入:

14 5 2 1 1 4 3 5 2 6 -1 4 0 2 -1 0 样例输出:

0 0 2 1 5 3 6 -1 2 0 分析:第一个需要注意的就是他给的输入输出并不是直接给出点坐标,但是容易发现的一个地方就是,第i个给出的点有两种情况,如果i是奇数,那么给出的就是纵坐标,否则就是横坐标,假如给出的是纵坐标,那么这个点的横坐标和上一个点的横坐标就是相同的,如果给出的是横坐标,那么这个点的纵坐标和上一个点的纵坐标就是相同的。处理完输入之后就是一个简单的模拟了,需要注意的一个坑点就是如果最后恰好到(0,0)那么不用再进行输出,这个地方需要特殊判断一下。

下面是代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e4+10;
int x[N],y[N]; 
int main()
{
	int n,l;
	cin>>n>>l;
	for(int i=1;i<=n;i++)
	{
		if(i&1)
		{
			scanf("%d",&y[i]);
			x[i]=x[i-1];
		}
		else
		{
			scanf("%d",&x[i]);
			y[i]=y[i-1];
		}
	}
	x[n+1]=0;y[++n]=0;
	int X=0,Y=0,ll=l;
	printf("0 0");
	for(int i=1;i<=n;i++)
	{
		int t=abs(x[i]-X)+abs(Y-y[i]);
		while(t>ll)
		{
			if(X==x[i])
			{
				if(y[i]-Y>0)
				{
					t-=ll;
					Y+=ll;
					ll=l;
				}
				else
				{
					t-=ll;
					Y-=ll;
					ll=l;
				}
			}
			else
			{
				if(x[i]-X>0)
				{
					t-=ll;
					X+=ll;
					ll=l;
				}
				else
				{
					t-=ll;
					X-=ll;
					ll=l;
				}
			}
			if(X||Y)
				printf("\n%d %d",X,Y);
		}
		if(X==x[i])
		{
			ll-=abs(Y-y[i]);
			Y=y[i];
		}
		else
		{
			ll-=abs(X-x[i]);
			X=x[i];
		}
		if(!ll)
		{
			if(X||Y)
				printf("\n%d %d",X,Y);
			ll=l;
		}
		
	}
	return 0;
}

7-2 队列插入

image.png 这道题目我写了一个暴力得了15分 15分代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e4+10;
long long a[N],b[N],dp[N];
char s[N],ans[N];
int tans;
int n;
int cal(int l,int r)
{
	memset(dp,0x3f,sizeof(dp)); 
    for(int i=l;i<=r;i++)
        *lower_bound(dp+1,dp+n+1,b[i])=b[i];//lower_bound是二分查找函数,当然也可以手写二分
    return (lower_bound(dp+1,dp+n+1,0x3f3f3f3f3f3f3f3f)-dp-1);
}
void dfs(int id,int l,int r)
{
	if(id==n+1)
	{
		int t=cal(l,r);
		if(t>tans)
		{
			tans=t;
			for(int i=1;i<=n;i++)
				ans[i]=s[i];
		}
		return ;
	}
	s[id]='L';
	b[l-1]=a[id];
	dfs(id+1,l-1,r);
	s[id]='R';
	b[r+1]=a[id];
	dfs(id+1,l,r+1);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	s[1]='L';b[1000]=a[1];
	dfs(2,1000,1000);
	printf("%d\n",tans);
	for(int i=1;i<=n;i++)
		printf("%c",ans[i]);
	return 0;
}

7-4猛犸不上 Ban(最短路)

image.png

分析:对于第二种选择显然直接跑一边最短路就可以了,这里就不多说了,下面主要说一下第一种选择。我一开始以为直接跑一个最短路就行,对于第一种说的回到s点,直接枚举与s存在直接边的j,求一个min(d[j]+dis[j][s])即可,但是发现样例都不对,模拟了一下发现存在重边,也就是说从s到j求最短路时经过了直接边s->j,所以就会产生错误,然后就发现思路错了,我就尝试了一下跑多次最短路,也就是对于每一个和s有直接边的j,我都直接跑一边最短路,但是这次最短路不能经过s->j这条边,然后我们再求一下d[j]+dis[j][s],最后取一个最小值即可。交了之后有一个超时,但是看了一下边数和点数,边数是1e5,点数是500,因为我写的是堆优化版的dijkstra,复杂度是O(mlogm),而这道题给的是一个稠密图,所以最好是用朴素版的最短路,直接换成朴素版的就能过了。复杂度是O(n^3)

细节见代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e6+10;
typedef pair<int,int>PII;
int d[N],n;
int p[503][503];
bool vis[N];
void dijkstra(int x,int u,int v)
{
	memset(vis,false,sizeof vis);
	memset(d,0x3f,sizeof d);
	d[x]=0;
	for(int i=1;i<n;i++)
	{
		int t=-1;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&(t==-1||d[t]>d[j])) t=j;
		vis[t]=true;
		for(int j=1;j<=n;j++)
		{
			if(t==u&&j==v) continue;
			if(d[j]>d[t]+p[t][j]) d[j]=d[t]+p[t][j];
		}
	}
}
int main()
{
	int m,s,t;
	cin>>n>>m>>s>>t;
	memset(p,0x3f,sizeof p);
	for(int i=1;i<=m;i++)
	{
		int u,v,t;
		scanf("%d%d%d",&u,&v,&t);
		p[u][v]=p[v][u]=t;
	}
	int t1=0x3f3f3f3f;
	for(int i=1;i<=n;i++)
	{
		if(i==s||p[i][s]==0x3f3f3f3f) continue;
		dijkstra(s,s,i);
		t1=min(t1,d[i]+p[i][s]);
	}
	dijkstra(s,0,0);
	int t2=d[t];
	if(t1==0x3f3f3f3f) printf("-1 ");
	else printf("%d ",t1);
	if(t2==0x3f3f3f3f) printf("-1\n");
	else printf("%d\n",t2);
	if(t1!=0x3f3f3f3f&&t1<t2) printf("Win!");
	else printf("Lose!");
	return 0;
}