【题解】「JOISC 2016 Day 2」三明治

思维 + 搜索

首先,如果你从四个角开始搜,对于每一个位置取最小值的话是不可做的。

所以我们明确思路:枚举起点 ( i , j ) (i,j) (i,j) ,考虑将所有需要走到的位置打上标记,记录所走过的节点个数即可。注意路径会有交叉,所以不能记忆化。时间复杂度 O ( n 4 ) O(n^4) O(n4)

void dfs(int x, int y, int dir) {
    if (x < 1 || x > r || y < 1 || y > c || tot == inf || step[x][y] == 1)
        return;

    if (step[x][y] == -1) {
        tot = inf;
        return;
    }

    step[x][y] = -1; //标记正在走过的点
    tot += 2;
    dfs(x + dx[dir << 1], y + dy[dir << 1], dir);

    if ((dir == 0 && mp[x][y] == 'N') || (dir == 1 && mp[x][y] == 'Z')) {
        dfs(x + dx[1], y + dy[1], (mp[x + dx[1]][y + dy[1]] == 'N') ? 0 : 1);
    } else {
        dfs(x + dx[3], y + dy[3], (mp[x + dx[3]][y + dy[3]] == 'N') ? 1 : 0);
    }

    step[x][y] = 1;
}

我们来观察这个搜索过程,发现有一个方向是必须走的,即 ( x + d x [ d i r < < 1 ] , y + d y [ d i r < < 1 ] , d i r ) (x+dx[dir<<1],y+dy[dir<<1],dir) (x+dx[dir<<1],y+dy[dir<<1],dir) ,而且方向也是固定的。

那么思路就很清晰了,我们可以直接继承上一状态所遍历到的所有位置,只需要改变一下枚举顺序:

for (int j = 1; j <= c; j++) {
    for (int k = 1; k <= r; k++) {
        for (int l = 1; l <= c; l++) {
            step[k][l] = 0;
        }
    }

    tot = 0;

    for (int i = 1; i <= r; i++) {
        dfs(i, j, 0);
        ans[i][j] = min(ans[i][j], tot);
    }

    for (int k = 1; k <= r; k++) {
        for (int l = 1; l <= c; l++) {
            step[k][l] = 0;
        }
    }

    tot = 0;

    for (int i = r; i >= 1; i--) {
        dfs(i, j, 1);
        ans[i][j] = min(ans[i][j], tot);
    }
}

时间复杂度 O ( n 3 ) O(n^3) O(n3)。至此,我们正确地解决了这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值