1.联通块
01迷宫
https://www.luogu.org/problemnew/show/P1141
暴力解法————咋呼
求联通块————perfect
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1000 + 99;
int n,m;
int flag[MAX][MAX];//flag保存每个点所在的联通图的编号(可以顺便表示出当前点访问过没有)
int arr[MAX][MAX];//各点的1/0
int ans[MAX*MAX];//保存每个联通图中点的个数(因为是联通的,所以这里面每个点都可以到达)
string tmp;
int cnt;//当前是在第几个联通图中
struct node{
int x,y;
};
queue <node> q;
int dx[5] = {0,0,-1,0,1};
int dy[5] = {0,-1,0,1,0};
int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) {
cin >> tmp;
for(int j = 0; j < n; j++) {
arr[i][j+1] = tmp[j] - '0';
// printf("%d ",arr[i][j+1]);
}
// printf("\n");
}
node e1,e2;
int nx,ny,x,y;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(!flag[i][j]) {//当前点不在已知的联通图中
cnt++;
ans[cnt] = 1;//初始化
flag[i][j] = cnt;
e1.x = i, e1.y = j;
q.push(e1);
while(!q.empty() ) {
e2 = q.front();
q.pop();
x = e2.x, y = e2.y ;
for(int k = 1; k <= 4; k++) {
nx = x + dx[k], ny = y + dy[k];
if(nx<=n && nx>=1 && ny<=n && ny>=1 && arr[nx][ny] != arr[x][y] && !flag[nx][ny])
{
ans[cnt]++;
flag[nx][ny] = cnt;
e1.x = nx, e1.y = ny;
q.push(e1);
}
}
}
}
}
}
int tmp2, tmp3;
for(int i = 1; i <= m; i++) {
scanf("%d%d",&tmp2,&tmp3);
printf("%d\n",ans[ flag[tmp2][tmp3] ]);
}
}
2.涂色法(最近太依赖BFS了,都忘了DFS的好处了)
- https://www.luogu.org/problemnew/show/P1506
- https://www.luogu.org/problemnew/show/P1162
ps: 两种做法 - 拯救oibh总部:标准涂色
/*
涂色法
*/
#include<bits/stdc++.h>
using namespace std;
string s[500+9];
int arr[500+9][500+9];
int x,y,nx,ny,ans;
int dx[] = {0, 0, -1, 0, 1};
int dy[] = {0, -1, 0, 1, 0};
void dfs(int a, int b) {
if(a<0 || a>x+1 || b<0 || b>y+1 || arr[a][b]) return ;//找既是陆地,有没涂过色的
arr[a][b] = 1;//1表示凃过色
for(int k = 1; k <= 4; k++) {
dfs(a+dx[k],b+dy[k]);
}
}
int main() {
scanf("%d%d",&x,&y);
for(int i = 1; i <= x; i++) {
cin >> s[i] ;
for(int j = 1; j <= y; j++) {
if(s[i][j-1] == '0') arr[i][j] = 0;
else arr[i][j] = 2;//2表示有障碍 /且 2 不是陆地
}
}
dfs(0,0);//虚拟外面还有 一层"总部",这样就可以不用麻烦去找真实总部外面没有墙的地方在哪
//直接就可以涂色
for(int i = 1; i <= x; i++) {
for(int j = 1; j <= y; j++) {
if(arr[i][j] == 0) // 没凃过色的 陆地 就是没有被淹没的点
{
ans++;
}
}
}
printf("%d",ans);
}
- 填涂颜色(另一种想法,本质上是一样的,就是可以换一种理解方式)
#include<bits/stdc++.h>
using namespace std;
const int MAX = 30 + 99;
int n;
int flag[MAX][MAX];
//思路: 从边界找“0” 并向外拓展,能够拓展得到的“0” 都不在圈内
int dx[5] = {0,0,-1,0,1};
int dy[5] = {0,-1,0,1,0};
void dfs(int x, int y) {
if(x<0 || x>n+1 || y<0 || y>n+1 || flag[x][y] == 1 || flag[x][y] == 2 )return ;
//先判断:超界或者遇到障碍或已经凃过色 都要回溯
flag[x][y] = 2;
for(int k = 1; k <= 4; k++) dfs(x+dx[k], y+dy[k]);
}
int main() {
scanf("%d",&n);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d",&flag[i][j]);//1 表示障碍
//这里的意图是只用一个数组表示全部 ,此时,我用的 2 表示涂过色
// 而 如果另加一个数组也许,用这个数组表示为“0”点的性质(即在圈内还是圈外)即可
}
}
//开始涂色
dfs(0,0);//依然是虚拟最最外层
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(flag[i][j] == 0) printf("2 ");
else if(flag[i][j] == 2) printf("0 ");//涂过色的都在圈外面
else printf("1 ");
}
printf("\n");
}
}