题目描述
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,天生擅长CSP,甚至有全国第一的水平! 但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图), 初始方向默认向上。宇宙射线会在发射出一段距离分裂,向该方向的左右45%方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂n次,每次分裂后会在分裂方向前进ai个单位长度。
现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击”。
Input
输入第一行包含一个正整数n(n <= 30),表示宇宙射线会分裂n次。
第二行包含n个正整数a1, a2…an,第i个数ai(ai <= 5)表示第i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。
Output
输出一个数ans,示有多少个位置会被降智打击。
样例
Input
4
4 2 2 3
Output
39
思路分析
这题最直接的想法肯定从起点开始进行,把每个到达的点都做个标记,求出不重复的点的个数,所以我用dfs进行搜索,这种方法的复杂度必然很高。
初始Dfs过程:当前点的横纵坐标为(a,b)分裂次数num,前进方向d。
1.若num等于最大分裂次数,回溯。
2.根据num确定前进长度,每次往前进方向走一个单位,并判断点是否到达。
3.-45°进行dfs。
4.+45°进行dfs。
用0~7来对应8个方向,用数组dx[],dy[]来计算坐标变化。(一开始还用字符串表示,map映射,分别写了八个函数什么的,太傻了)
-45°:(d+1)%8;
+45°:(d+7)%8;
所以我们进行合理的剪枝。首先我想到的就是同一个点往同一个方向,并且前进长度相同时就可以剪掉,并且用了几个例子感觉都对,但一交就是WA,这种剪枝存在的问题是,就算同一个方向、前进长度相同,它的下一次分裂也会前进不同的长度。所以要考虑到分裂次数,同一个点往同一个方向,并且在同一次分裂时就可以剪掉,也不会影响后续的分裂。(其实这种一开始想到了,但觉得前一种可以剪掉更多的情况,却没有考虑到对后续分裂的影响)。
用二维数组reach来标记是否到达,四维数组divide来标记分裂情况。在dfs过程中,若当前点对应四维数组中元素为1,则回溯。
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
/*
struct point
{
int a,b;
point(){}
point(int x,int y)
{
a=x;b=y;
}
bool operator<(const point &p) const
{
if(a!=p.a) return a<p.a;
else
return b<p.b;
}
};
struct point1
{
int a,b;
int num;//分裂次数
int d;//分裂方向
point1(){}
point1(int x,int y,int Num,int D)
{
a=x;b=y;num=Num;d=D;
}
bool operator<(const point1 &p1) const
{
if(a!=p1.a) return a<p1.a;
else
{
if(b!=p1.b) return b<p1.b;
else
{
if(num!=p1.num) return num<p1.num;
else
{
if(d!=p1.d) return d<p1.d;
}
}
}
}
};*/
int n,ans=0,count[30];
int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,1,0,-1,-1,-1,0,1};
//map<point,bool> reach;//是否到达
//map<point1,bool> divide;//分裂情况
int reach[400][400]={0};
int divide[400][400][5][8]={0};
int tag=0;
void dfs(int a,int b,int num,int d)
{
if(num==n) return;//停止分裂
if(divide[a][b][num][d]==1) return;
//在此次分裂中已经向同方向分裂过了不必再分裂了
divide[a][b][num][d]=1;
for(int i=0;i<count[num];i++)
{
a+=dx[d];
b+=dy[d];
if(reach[a][b]==0)
{
reach[a][b]=1;
ans++;
//printf("%d %d %d %d\n",p.a,p.b,num,d);
}
}
dfs(a,b,num+1,(d+7)%8);//-45
dfs(a,b,num+1,(d+1)%8);//+45
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&count[i]);
}
dfs(200,200,0,0);
printf("%d %d",ans,tag);
return 0;
}