题目概述
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进ai个单位长度。现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。
输入输出
Input
输入第一行包含一个正整数 n(n<=30),表示宇宙射线会分裂n 次
第二行包含n个正整数a1,a2···an ,第ai 个数(ai<=5)表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度
Output
输出一个数ans ,表示有多少个位置会被降智打击
Sample Input
4
4 2 2 3
Sample Output
39
思路分析
这道题csp模测的时候我没写到,结束后看到大佬在群里讨论说用dfs剪枝就行了,因此少走了一些弯路哈哈。
剪枝的实现是定义一个布尔类型的四维数组,利用对称的性质,同一个位置(x,y)同一层同方向是重复的只做一遍就行了。
对于是否走过某点用map.count(key)函数实现,没走过返回0,ans++,将该点加入map;走过则返回1。
具体看代码。
注意
注意起点坐标,是自己设定的,与judge数组中x y的范围匹配起来。因为最多30次分裂且每次分裂前最多走5步,因此若从中心发射,上下左右最多各需要150格,因此这里定义的四维数组的坐标x,y的范围均为400,起点坐标从(200,200)开始。
代码
#include<iostream>
#include<map>
using namespace std;
int n,ans=0;
int a[31];
//射线共8个方向:上、右上、右、右下、下、左下、左、左上
int dx[]={0,1,1,1,0,-1,-1,-1};
int dy[]={1,1,0,-1,-1,-1,0,1};
bool judge[400][400][31][8]={false};
struct point{
int x,y;
bool operator<(const point &p)const{
return x!=p.x? x<p.x:y<p.y;
}
};
map<point,int> mp;
void solve(point p,int k,int flag)
{//k记录层数,flag记录当前射线的方向
if(k>=n) return;
int x=p.x,
y=p.y;
if(judge[x][y][k][flag]) return;
judge[x][y][k][flag]=true;
for(int i=0;i<a[k];i++)
{//每一层走指定的步数,每一步的方向都是flag
x+=dx[flag];
y+=dy[flag];
point p1;
p1.x=x;
p1.y=y;
if(mp.count(p1)==0){
//如果没走过该点
ans++;
mp[p1]=1;
}
}
point p2;
p2.x=x;
p2.y=y;
//分别向左右45度方向分裂
solve(p2,k+1,(flag+7)%8);
solve(p2,k+1,(flag+1)%8);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
solve({200,200},0,0);
cout<<ans<<endl;
return 0;
}