程序设计思维与实践 Week4 模拟赛 C 可怕的宇宙射线

题目描述:

众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天 生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁 人的智商,进行降智打击! 宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的 左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进 个单位长度。 现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生 那么菜的水平,所以瑞神来请求你帮他计算出共有多 少个位置会被"降智打击"

输入描述:

输入第一行包含一个正整数 ,表示宇宙射线会分裂n次.第二行包含n个正整数a1 a2 .... an,第i个数ai表示第i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。

输出描述:

输出一个数 ,表示有多少个位置会被降智打击

思路:

在模拟赛中,我观察到了n的值非常大,最终的分裂次数为2^30,但是又想不出绝妙的算法,最终写了个暴力模拟,这样可以得到40分,但是不幸的是,模拟写wa了......

这道题可以通过深度优先搜索+记忆化的方式来做,在2^30次分裂过程中,会有许许多多的情况是同样的,即:有a和b,a进行了第i次分裂,方向为d,起点是x y,而b也将要进行第i次分裂,方向为d,起点也恰好是x y。可以看出,a和b的路径是完全相同的,之后两者继续分裂所造成的影响也是相同的。那么就可以通过记忆化的方式,将a的分裂情况记录下来,后来者b再次分裂时,就可以直接忽略。

#include<iostream>
#include<cstdio>
using namespace std;
int n,ans,a[31];
int xx[8]={0,1,1,1,0,-1,-1,-1};
int yy[8]={1,1,0,-1,-1,-1,0,1};
bool flag[600][600],vis[600][600][31][8];
void dfs(int x,int y,int now,int d)//xy表示位置,now是当前为第几次分裂,d是分裂的方向。 
{
	if(now>n||vis[x][y][now][d])
	return;
	vis[x][y][now][d]=1;
	for(int i=1;i<=a[now];i++)
	{
		x+=xx[d];y+=yy[d];
		if(!flag[x][y])
		{
			flag[x][y]=1;
			ans++;
		}
	}
	dfs(x,y,now+1,(d+7)%8);
	dfs(x,y,now+1,(d+1)%8);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	dfs(300,300,1,0);
	printf("%d",ans);
	return 0;
}
发布了277 篇原创文章 · 获赞 222 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/cax1165/article/details/104856009
今日推荐