BFS:射线分裂问题。c++

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

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

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

sample input:
4
4 2 2 3

sample output:
39

图示:

思路:

  • 对于所有的点,只可能有八种前进方向。并且每次只可能是逆时针和顺时针的45度,所以可以按照顺时针或者逆时针的方向对应写出x,y坐标的变化,这样只需要记录下每一次的转变方向,就可以通过%8+1和-1的方式得到这次的转向。
  • 可以利用一个bool型二维数组hit[x][y]来表示这个坐标(x,y)是否被访问到,最后计算hit的点的数量即可得到答案
  • 利用广搜的方式,对于每一个分支节点进行两个递归继续搜索
  • 如果直接按照上面的思路的话,可以过5个点,其余的点会TLE,为了降低时间复杂度,我们需要对现在的程序进行剪枝
  • 程序消耗的时间过多的主要原因是,当点的数量较大的时候,可能会出现在进行某一层时,同时有几个分支到达了同一个点,那么对于同样的点,不同的分支都会将他走到最后去,导致了很多的冗余。所以创建一个四维数组,用来表示在某一层的某一个点上的某个方向,如果同样的点出现,就直接跳出。
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int dirx[8]={0,-1,-1,-1,0,1,1,1};
int diry[8]={1,1,0,-1,-1,-1,0,1};//一圈方便循环 
int ans=0;
int t[31];
int n;
bool hit[400][400]={false};
bool visit[31][400][400][8]; 
void digui(int now,int x,int y,int d)
{
	if(visit[now][x][y][d]==true)//降低复杂度 
	return;
	visit[now][x][y][d]=true;
	if(!hit[x][y])
	{
		hit[x][y]=true;
		ans++;
	}
	int temp_x=x,temp_y=y;
	for(int i=0;i<t[now]-1;i++)
	{
		temp_x+=dirx[d];
		temp_y+=diry[d];
		if(!hit[temp_x][temp_y])
		{
			hit[temp_x][temp_y]=true;
			ans++;
		}
	}
	if(now==n) return;//返回条件 
	int temp_d=(d+1)%8;//45
	digui(now+1,temp_x+dirx[temp_d],temp_y+diry[temp_d],temp_d);
	temp_d=(d+7)%8;
	digui(now+1,temp_x+dirx[temp_d],temp_y+diry[temp_d],temp_d);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>t[i];
	digui(1,200,200,0);//第一个的方向肯定是向上 
	cout<<ans;
	return 0;
}
发布了29 篇原创文章 · 获赞 1 · 访问量 948

猜你喜欢

转载自blog.csdn.net/qq_44654498/article/details/104884548