dfs-宇宙射线问题

题目描述

宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变。宇宙射线会分裂n次,每次分裂后会在分裂方向前进ai 个单位长度。计算出共有多少个位置会被打击。

Input

输入第一行包含一个正整数n(n <= 30),表示宇宙射线会分裂n次,第二行包含n个正整数a1,a2…an,第i个数ai(ai <= 5)表示第i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。

Output

输出一个数ans,表示有多少个位置会被降智打击。

Sample Input

4
4 2 2 3

Sample Output

39

解题思路

本题思路容易想到,通过bfs或者dfs直接搜索。但在这之前,要先用一个二维数组存储该网格中的每个点是否到达。由于刚开始使用的是bfs,但最后总是报错(对不起,是我太菜),后来就使用了dfs,并用记忆化搜素记录搜索过的路径,来进行“剪枝”操作,降低时间复杂度。
除此之外,此题中一个难以解决的是方向问题,但经过仔细分析后,发现八个方向是有规律的,用一个数组有规律的存储这八个方向,则可以发现如果将方向数组看成环,那么每个方向结束后的下面两个方向都是环中前后各一个方向,这样就确定了下一次的偏移。

代码

#include<iostream>
#include<string>
#include<queue>
#include<cmath>
using namespace std;
//int graph[300][300];
bool arr[300][300][30][8]={false};
bool arr2[300][300]={false};
struct node
{
	int x,y;
};
 
int ans=0;
node dir[8] = {{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};//按照左下,左,左上,上,右上,右,右下,下的顺序排列 
void search(node start,int d,node dir2,int m,int *a,int n)
{
	if(m==n)
    {
    	return ;
	}
	if(arr[start.x][start.y][m][d]==true)//如果和之前的轨迹完全重合,则可以直接跳过 
    {  
        return;
    }
    arr[start.x][start.y][m][d]=true;//存在这条路径 
//    ans++;
	for(int i=0;i<a[m];i++)
	{
		start.x+=dir2.x;
		start.y+=dir2.y;
		if(arr2[start.x][start.y]!=true)
		{
			arr2[start.x][start.y]=true;
			ans++;
		}

	}
	search(start,(d+1)%8,dir[(d+1)%8],m+1,a,n);//右边的方向 
	search(start,(d+7)%8,dir[(d+7)%8],m+1,a,n);//左边的方向 

}
int main()
{
	int n;
	cin>>n;
	int a[30];
	for(int i=0;i<n;i++)
	    cin>>a[i];
	node start={150,150};//起点 
	node dir2=dir[3];//第一次的方向 
//	int m=0;//递归次数 
	search(start,3,dir2,0,a,n);//四个参数分别是每次递归的起点,每一次移动的个数,第几次递归,总递归次数,每次递归的起点 
    cout<<ans<<endl;
	return 0;
 } 

反思

本题中的记忆化搜索在之前是没有关注过的,或者说没发现其妙处。但在此题中,刚开始并没有使用记忆化搜索时,发现会超时。但在利用记忆化搜索进行“剪枝”后,时间立马降了下来。后来想起来迷宫问题也用过类似的操作。以后可以常用!

发布了16 篇原创文章 · 获赞 0 · 访问量 215

猜你喜欢

转载自blog.csdn.net/weixin_43679657/article/details/105027707
今日推荐