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;
}

posted @ 2022-02-04 10:05  Bellala  阅读(22)  评论(0编辑  收藏  举报