程序设计思维与实践 CSP-M1 C-可怕的宇宙射线

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

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

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

Sample Input:
4
4 2 2 3

Sample Output:
39

Hint:

数据点 n
10% 小于等于10
40% 小于等于20
100% 小于等于30

图示

思路:
本题是dfs操作,而且要进行“剪枝”操作,即已访问的的点返回,记录的数组是四维的。
通过观察,射线的分裂具有对称性,因此在记录过程中相同层数的分裂状态是不需要重复考虑的,同时每次经过的路径用vis数组记录,防止路径叠加。
对于分裂的两个方向用两个方向数组表示,每次分裂之后的距离不确定,因此循环距离,每循环一次,ans++,然后进行递归,分裂次数+1,用sens表示从上一层分裂的方向。

总结:
本题使用四维数组进行“剪枝”操作,是为了防止时间复杂度过大,因为数据达到了2^30,如果普通搜索时间复杂度将会是指数级别的。起初我用int型四维数组进行初始化记录,发现内存占用过大,就使用bool类型解决,而且在最初考虑时没有注意到平面中会重复。写程序之前要把题目所要求的每个点进行分析考虑,这样编写程序的效率会大大提高。

代码:

#include<iostream>
#include<utility>
using namespace std;
bool vis[500][500][30][8],flag[500][500];
int n,ans,a[40],x[8]={0,1,1,1,0,-1,-1,-1},y[8]={1,1,0,-1,-1,-1,0,1};
void dfs(pair<int,int> pos,int count,int sens){
	if(count>n)
		return;
	if(vis[pos.first][pos.second][count][sens])
		return;
	vis[pos.first][pos.second][count][sens]=true;
	for(int i=0;i<a[count];i++){
		pos.first+=x[sens];
		pos.second+=y[sens];
		if(!flag[pos.first][pos.second]){
			ans++;
			flag[pos.first][pos.second]=true;
		}
	}
	pair<int,int> u(pos.first,pos.second);
	dfs(u,count+1,(sens+1)%8);
	dfs(u,count+1,(sens+7)%8);
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>a[i];
	pair<int,int> pos(200,200);
	dfs(pos,0,0);
	cout<<ans<<endl; 
} 

发布了24 篇原创文章 · 获赞 0 · 访问量 511

猜你喜欢

转载自blog.csdn.net/qq_43666020/article/details/104928416