题目描述:
众所周知,瑞神已经达到了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;
}