P1141 01迷宫
首先是读入上的问题,这里可以使用二维字符数组存储这张图,但也可以使用
scanf("%1d",&maze[i][j]);
人为规定读入数据长度
从整体方法看,很明显的搜索问题,使用BFS和DFS都可以,但还是DFS好写
但实际上手后发现三个点超时,想了想是由于大量重复计算导致的
然后就发现实际上这题是一个联通块问题,所有联通的的格子的答案是相同的
于是需要一个方式来维护连通格子的答案
首先想到的是记忆化搜索,每个格子只执行一边操作,核心代码如图
void DFS(int i, int j, int marker ,int ll){ //i,j为坐标,marker记录从1还是0格子来的,ll记忆化
if(maze[i][j] == -1 || vis[i][j] != -1 || !(marker ^ maze[i][j])) return ; //分别是 边界(通过memeset使图周围一圈为-1) 重复情况 是否为0到1或1到0
vis[i][j] = ll; //将本次联通的格子全部指向ll
ans[ll]++;
DFS(i + 1, j, maze[i][j], ll);
DFS(i, j + 1, maze[i][j], ll);
DFS(i, j - 1, maze[i][j], ll);
DFS(i - 1, j, maze[i][j], ll);
}
for(i = 1; i <= m; i++){
cin >> x >> y;
if(vis[x][y] == -1) DFS(x,y,1 ^ maze[x][y], i);
else ans[i] = ans[vis[x][y]];
cout << ans[i] << endl;
}
然后思索了一下,想到了并查集,和记忆化异曲同工,但在储存时不会用pair(恼火) ,借鉴了一位大佬的二维坐标转数字
即 因为( i , j < n )所以将 i * n + j 便可以使每个坐标都转换为独一无二的数字
这个函数短小且需大量调用,所以使用内联函数inline来节省时间
inline int vti(int x, int y) return y * n + x;
剩下就是细心写并查集了
int find(int k){
if(f[k] == k) return k;
else return f[k] = find(f[k]);
}
void bin(int i, int j){
f[find(i)] = find(j);
}//并查集标准代码
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++){
if(maze[i][j] + maze[i + 1][j] == 1)
bin(vti(i,j), vti(i+1,j));
if(maze[i][j] + maze[i][j + 1] == 1)
bin(vti(i,j), vti(i,j+1));
} //逐个方块向右,向下扩展
}
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
ans[find(vti(i,j))]++; //记录联通块数量并储存在老大的ans中
for(i = 1; i <= m; i++){
cin >> x >> y;
cout << ans[find(vti(x,y))] << endl;
}
但既然谈到了联通块,我隐约回忆起tarjan算法,等我复习回来看看能不能再写一种解法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现