宇宙射线
问题分析
题干说明是每条射线都会分成两条射线,一条顺时针转45度,一条逆时针转45度。即每条路径都会另分出两条路径,我们要做的是遍历每条路径并计算走的不同位置。使用bfs或dfs都可达成目的,此处采用dfs思想。
首先需要解决不同方向的表示问题,一开始直接枚举了八种方向分别判断,但是写出代码后发现过于冗杂,代码重复度很高,于是总结在不同方向前进时,x,y的变化规律,写入数组。
首先对各个方向进行编号,方便我们通过索引访问,如图
一开始方向为向上,即0号,他分出的两条路径为1号和7号,求逆时针转45度:(0+1)%8;求顺时针转45度:(0+7)%8。处理其他方向同理。
接着,我们总结在各个方向前进x,y的坐标变化:(数组索引与图中方向编号对应)
int angx[8] = {1, 1, 0,-1,-1,-1, 0, 1};
int angy[8] = {0,-1,-1,-1, 0, 1, 1, 1};
因为本题数据指数级增长,数据量大,一开始没有进行剪枝,一直超时。思考本题中可能的重复数据,因为数据量大,因此完全可能存在一种情况,两个点的坐标相同,前进方向相同,前进步数也相同。
为排除这种情况,采用了四维数组,四个维度分别为:前进步数、x坐标,y坐标,前进方向。初始化为false,在每个起始点首先检查是否为true,如果是,说明重复,直接返回。否则更新为true。
具体代码如下:
代码实现(dfs递归)
#include<stdio.h>
#include<queue>
#include<math.h>
using namespace std;
struct point
{
int x;
int y;
};
int angx[8] = {1, 1, 0,-1,-1,-1, 0, 1};
int angy[8] = {0,-1,-1,-1, 0, 1, 1, 1};
int n=0;
int *a;
int r[400][400]={0};
bool vis[31][400][400][8] ={false};
int ans=0;
void radio(int index,point b,int ang)
{
int sx = b.x;
int sy = b.y;
if(index == n) return; //结束返回条件
if(vis[index][sx][sy][ang] == true) return;//剪枝
vis[index][sx][sy][ang] = true;
for(int j=0; j<a[index]; j++)
{
if(r[sx][sy] == 0)
{
r[sx][sy] = 1;
ans++;
}
sx += angx[ang];
sy += angy[ang];
}
sx -= angx[ang];
sy -= angy[ang];
point s;
int temp = (ang+1)%8;//逆时针45
s.x = sx+angx[temp];
s.y = sy+angy[temp];
radio(index+1,s,temp);
temp = (ang+7)%8;
s.x = sx+angx[temp];
s.y = sy+angy[temp];
radio(index+1,s,temp);
}
int main()
{
scanf("%d",&n);
a = new int[n];
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
point t;
t.x=200;
t.y=200;
radio(0, t, 0);
printf("%d\n",ans);
return 0;
}