第一次模拟测试-3

题目描述:
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天 生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁 人的智商,进行降智打击! 宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的 左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进 个单位长度。 现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生 那么菜的水平,所以瑞神来请求你帮他计算出共有多 少个位置会被"降智打击"
输入格式:
输入第一行包含一个正整数 ,表示宇宙射线会分裂n次.第二行包含n个正整数a1 a2 … an,第i个数ai表示第i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。
输出格式:
输出一个数 ,表示有多少个位置会被降智打击
题目思路:
这个题目比较麻烦的一点就是有些路径会重合,所以并不是单纯的利用等比函数来计算,而是要用dfs。
首先我们要绘制一张大的二维数组记录位置,这样每走过一个点就记录一个位置,如果发现这个位置走过了就不用再计数了。
题目里描述的是分裂方向,所以我们要处理两个方向,我们发现对于方向来说有八组,每一组对应的是每个方向分裂后的结果

int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,1,0,-1,-1,-1,0,1};

这样我们每次调用dfs的时候只需要用两个方向即可
每次按照分裂之后的长度走一段距离,然后标记走过的路径,如果没走过就结果++,重新分裂继续前进,直到走到头了为止

void dfs(int x,int y,int now,int direction)
{
	if(now>n||visit[x][y][now][direction]==1)
	return ;
	visit[x][y][now][direction]=1;
	for(int i=1;i<=a[now];i++)
	{
		x=x+dx[direction];
		y=y+dy[direction];
		if(flag[x][y]==0)
		{
			flag[x][y]=1;
			ans++;
		}
	}
	dfs(x,y,now+1,(direction+1)%8);
	dfs(x,y,now+1,(direction+7)%8);
}

代码如下:

#include<iostream>
using namespace std;
int n,ans,a[31];
int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,1,0,-1,-1,-1,0,1};
bool visit[600][600][31][8];//需要注意这个数组很大,用int直接MLE
bool flag[600][600];
void dfs(int x,int y,int now,int direction)
{//x,y为当前位置,now为到哪一次分裂了,direction为方向
	if(now>n||visit[x][y][now][direction]==1)
	return ;
	visit[x][y][now][direction]=1;
	for(int i=1;i<=a[now];i++)
	{
		x=x+dx[direction];
		y=y+dy[direction];
		if(flag[x][y]==0)
		{
			flag[x][y]=1;
			ans++;
		}
	}
	dfs(x,y,now+1,(direction+1)%8);//取模就可以进行循环,保证取值范围
	dfs(x,y,now+1,(direction+7)%8);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	dfs(300,300,1,0);//为了方便初始我们从中间开始计数
	cout<<ans; 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值