【题解】「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)。至此,我们正确地解决了这个问题。


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530333.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示