cf750D. New Year and Fireworks(dfs)
题意:
网格中有一个递归烟花。开始1个烟花从某点开始往上走 \(t_1\) 格,然后爆成2个。这两个烟花分别朝左上、右上走 \(t_2\) 格,然后分别爆成2个(现在一共4个),并朝原烟花方向的左上、右上走 \(t_3\) 格。给定 \(n\) 和 \(t_i\),烟花一共爆炸 \(n-1\) 次,求烟花走过的格子数。
\(1\le n \le 30 , 1\le t_i\le 5\)
思路:
如果一直直走,能走到的最远处为 \(nt_i=150\),所以只用考虑 \(300\times 300\) 的网格。
dfs模拟,8个方向逆时针或顺时针存,复杂度是 \(2^n\)。考虑剪枝,之前到过的的状态就不遍历了。
状态要包括位置、方向、爆炸次数(即递归深度depth)、直走的步数。
这样网格中每个点最多被访问 \(8n\) 次(8个方向和 \(n\) 个深度)
const int N = 33, M = 310;
int dx[] = {1,1,0,-1,-1,-1,0,1}, dy[] = {0,1,1,1,0,-1,-1,-1};
bool g[M][M], vis[M][M][8][N][6]; //x,y,dir,depth,step
int n, t[N], ans;
void dfs(int x, int y, int dir, int depth, int step)
{
if(depth > n) return;
if(vis[x][y][dir][depth][step]) return; vis[x][y][dir][depth][step] = 1;
if(!g[x][y]) ans++, g[x][y] = 1;
if(step < t[depth]) //直走
dfs(x + dx[dir], y + dy[dir], dir, depth, step + 1);
else //转向
dfs(x, y, (dir+1)%8, depth + 1, 0),
dfs(x, y, (dir-1+8)%8, depth + 1, 0);
}
signed main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> t[i];
dfs(150, 150, 0, 1, 1);
cout << ans;
}