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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章