【记忆化搜索】可怕的宇宙射线

问题描述

众所周知,瑞神已经达到了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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值