问题描述
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂n 次,每次分裂后会在分裂方向前进 ai个单位长度。
现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。
Input
输入第一行包含一个正整数n(n<=30) ,表示宇宙射线会分裂n次。
第二行包含n个正整数a1,a2…an,第 i个数ai 表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。
Output
输出一个数 ans,表示有多少个位置会被降智打击。
Sample
Input
4
4 2 2 3
Output
39
思路
230的复杂度直接搜索是会超时的,故我们要么剪枝要么采用记忆化。本题并没有明显剪枝,故采用记忆化,我们发现每一轮分裂在x,y位置的,方向为f的,分裂长度为l的点不必再搜,记忆数组大小是30 * 300 * 300 * 8 * 5,空间允许,时间复杂度也是这些。除此之外,由于覆盖点过于密集(230的复杂度300 * 300的地图),利用本题对称的性质,dfs求解,对于每一轮的另一半采用对称的方式把求取另一半的覆盖点,这是一种很优的做法。
代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<queue>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define mem(a,s) memset(a,s,sizeof(a))
int map[301][301];
bool b[31][301][301][8][6]={0};
int a[31];
int n,ans=0;
int fx[8]={0,-1,-1,-1,0,1,1,1};
int fy[8]={-1,-1,0,1,1,1,0,-1};
struct node{
int t,x,y,f;
node(int _t,int _x,int _y,int _f)
:t(_t),x(_x),y(_y),f(_f){}
};
void bfs(){
queue<node> q;
node p(1,150,150,0);
q.push(p);
while(!q.empty()){
p = q.front();q.pop();
int x=p.x,y=p.y,f=p.f,t=p.t;
rep(i,1,a[t]){
x+=fx[f];y+=fy[f];
if(map[x][y]==0){
map[x][y]=1;
ans++;
}
}
if(t<n){
if(!b[t+1][x][y][(f+1)%8][a[t+1]]){
b[t+1][x][y][(f+1)%8][a[t+1]]=1;
node pp(t+1,x,y,(f+1)%8);
q.push(pp);
}
if(!b[t+1][x][y][(f+7)%8][a[t+1]]){
b[t][x][y][(f+7)%8][a[t+1]]=1;
node pp(t+1,x,y,(f+7)%8);
q.push(pp);
}
}
}
}
int main(){
// freopen("1.txt","r",stdin);
mem(map,0);
cin >> n;
rep(i,1,n){
cin>>a[i];
}
bfs();
cout<<ans;
return 0;
}