宝岛探险–着色法
要求
0代表海洋,1~9代表陆地,飞机降落在(5, 7)处,开始探索,统计探索的面积(格子数)。
思路
从(5, 7)处开始广度优先搜索,被加入队列的点的总数就是小岛面积。
bfs代码
#include <stdio.h>
#define N 10
#define M 10
int a[N][M] = {
{1, 2, 1, 0, 0, 0, 0, 0, 2, 3},
{3, 0, 2, 0, 1, 2, 1, 0, 1, 2},
{4, 0, 1, 0, 1, 2, 3, 2, 0, 1},
{3, 2, 0, 0, 0, 1, 2, 4, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 5, 3, 0},
{0, 1, 2, 1, 0, 1, 5, 4, 3, 0},
{0, 1, 2, 3, 1, 3, 6, 2, 1, 0},
{0, 0, 3, 4, 8, 9, 7, 5, 0, 0},
{0, 0, 0, 3, 7, 8, 6, 0, 1, 2},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
};
int b[N][M] = {0};
struct node
{
int x;
int y;
};
struct node que[401]; // 地图大小不超过20*20
int head = 0, tail = 0;
void enqueue(struct node p) {
que[tail] = p;
tail++;
}
struct node dequeue() {
head++;
return que[head-1];
}
int is_empty() {
return head == tail;
}
void print_a() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
printf("\n");
}
void print_b() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%d ", b[i][j]);
}
printf("\n");
}
printf("\n");
}
int main() {
int sum = 0;
struct node p = {5, 7};
enqueue(p);
b[p.x][p.y] = 1;
sum++;
while(!is_empty()) {
p = dequeue();
// bfs 搜索可以探险的点
if (a[p.x][p.y+1] != 0 && b[p.x][p.y+1] == 0 && p.y+1 < M) {
struct node temp = {p.x, p.y+1};
enqueue(temp);
b[p.x][p.y+1] = 1;
sum++;
}
if (a[p.x+1][p.y] != 0 && b[p.x+1][p.y] == 0 && p.x+1 < N) {
struct node temp = {p.x+1, p.y};
enqueue(temp);
b[p.x+1][p.y] = 1;
sum++;
}
if (a[p.x][p.y-1] != 0 && b[p.x][p.y-1] == 0 && p.y-1 >= 0) {
struct node temp = {p.x, p.y-1};
enqueue(temp);
b[p.x][p.y-1] = 1;
sum++;
}
if (a[p.x-1][p.y] != 0 && b[p.x-1][p.y] == 0 && p.x-1 >= 0) {
struct node temp = {p.x-1, p.y};
enqueue(temp);
b[p.x-1][p.y] = 1;
sum++;
}
}
print_a();
print_b();
printf("sum: %d\n", sum);
return 0;
}
思路
也可以使用深度优先搜索,下面使用递归的方式实现深度优先搜索。
dfs代码
#include <stdio.h>
#define N 10
#define M 10
int a[N][M] = {
{1, 2, 1, 0, 0, 0, 0, 0, 2, 3},
{3, 0, 2, 0, 1, 2, 1, 0, 1, 2},
{4, 0, 1, 0, 1, 2, 3, 2, 0, 1},
{3, 2, 0, 0, 0, 1, 2, 4, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 5, 3, 0},
{0, 1, 2, 1, 0, 1, 5, 4, 3, 0},
{0, 1, 2, 3, 1, 3, 6, 2, 1, 0},
{0, 0, 3, 4, 8, 9, 7, 5, 0, 0},
{0, 0, 0, 3, 7, 8, 6, 0, 1, 2},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
};
int b[N][M] = {0};
int sum = 0;
struct node
{
int x;
int y;
};
void print_a() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
printf("\n");
}
void print_b() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%d ", b[i][j]);
}
printf("\n");
}
printf("\n");
}
void dfs(struct node p) {
if (a[p.x][p.y+1] != 0 && b[p.x][p. y+1] == 0 && p.y+1 < M) {
b[p.x][p.y+1] = 1;
sum++;
struct node temp = {p.x, p.y+1};
dfs(temp);
}
if (a[p.x+1][p.y] != 0 && b[p.x+1][p.y] == 0 && p.x+1 < N) {
b[p.x+1][p.y] = 1;
sum++;
struct node temp = {p.x+1, p.y};
dfs(temp);
}
if (a[p.x][p.y-1] != 0 && b[p.x][p.y-1] == 0 && p.y-1 >= 0) {
b[p.x][p.y-1] = 1;
sum++;
struct node temp = {p.x, p.y-1};
dfs(temp);
}
if (a[p.x-1][p.y] != 0 && b[p.x-1][p.y] == 0 && p.x-1 >= 0) {
b[p.x-1][p.y] = 1;
sum++;
struct node temp = {p.x-1, p.y};
dfs(temp);
}
}
int main() {
struct node p = {5, 7};
dfs(p);
print_a();
print_b();
printf("sum: %d\n", sum);
return 0;
}
总结
以上方法叫做着色法,以某个点为源点对其邻近的点进行着色。应用场景有:ps的魔术棒工具。
扩展–漫水填充法
求地图中又多少个独立的小岛?(求一个图中独立子图的个数)
思路
枚举法对地图上每一个大于0的点进行一遍深度优先搜索。
代码
#include <stdio.h>
#define N 10
#define M 10
int a[N][M] = {
{1, 2, 1, 0, 0, 0, 0, 0, 2, 3},
{3, 0, 2, 0, 1, 2, 1, 0, 1, 2},
{4, 0, 1, 0, 1, 2, 3, 2, 0, 1},
{3, 2, 0, 0, 0, 1, 2, 4, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 5, 3, 0},
{0, 1, 2, 1, 0, 1, 5, 4, 3, 0},
{0, 1, 2, 3, 1, 3, 6, 2, 1, 0},
{0, 0, 3, 4, 8, 9, 7, 5, 0, 0},
{0, 0, 0, 3, 7, 8, 6, 0, 1, 2},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
};
int b[N][M] = {0};
int sum = 0;
struct node
{
int x;
int y;
};
void print_a() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%3d ", a[i][j]);
}
printf("\n");
}
printf("\n");
}
void print_b() {
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%3d ", b[i][j]);
}
printf("\n");
}
printf("\n");
}
void dfs(struct node p, int color) {
a[p.x][p.y] = color;
if (a[p.x][p.y+1] != 0 && b[p.x][p. y+1] == 0 && p.y+1 < M) {
b[p.x][p.y+1] = 1;
sum++;
struct node temp = {p.x, p.y+1};
dfs(temp, color);
}
if (a[p.x+1][p.y] != 0 && b[p.x+1][p.y] == 0 && p.x+1 < N) {
b[p.x+1][p.y] = 1;
sum++;
struct node temp = {p.x+1, p.y};
dfs(temp, color);
}
if (a[p.x][p.y-1] != 0 && b[p.x][p.y-1] == 0 && p.y-1 >= 0) {
b[p.x][p.y-1] = 1;
sum++;
struct node temp = {p.x, p.y-1};
dfs(temp, color);
}
if (a[p.x-1][p.y] != 0 && b[p.x-1][p.y] == 0 && p.x-1 >= 0) {
b[p.x-1][p.y] = 1;
sum++;
struct node temp = {p.x-1, p.y};
dfs(temp, color);
}
}
int main() {
int i, j;
int num = -1;
for (i = 0; i < N; ++i) {
for (j = 0; j < M; ++j) {
if (a[i][j] > 0){
struct node p = {i, j};
dfs(p, num--);
}
}
}
print_a();
print_b();
printf("sum: %d\n", sum);
return 0;
}