LINK:https://vjudge.net/problem/POJ-2386
Given a diagram of Farmer John's field, determine how many ponds he has.
* Lines 2..N+1: M characters per line representing one row of Farmer John's field. Each character is either 'W' or '.'. The characters do not have spaces between them.
10 12 W........WW. .WWW.....WWW ....WW...WW. .........WW. .........W.. ..W......W.. .W.W.....WW. W.W.W.....W. .W.W......W. ..W.......W.Sample Output
3Hint
There are three ponds: one in the upper left, one in the lower left,and one along the right side.
题目大概说的是 八方联通块的问题 就是看有多少个水洼 肉眼看上去就是3块 嘛! 感觉不难 找到其中一个 然后八方检测 检测到以后就标记好 在来一次八方检测 直到 全部都不满足的时候 这就是 一个水洼的全部都赋值完毕了。
我叫: 牵一发而动全身的题目。
1.首先我们需要准备 一个 vis[][] 数组 这个数组是作为标记 这个点是不是被访问到的。如果被访问到了,我们就设置这个数组。我把它放在全局变量下是因为 我看重它在全局变量下 各个值都是为0 的关系 也就是 false 。就不用memset了。
2.然后我考虑到八方检测 那没得说的 八方检测 什么是八方检测呢??就是八个方向依次访问,听学长说就是来一波排列组合 我没有学长那么精明 所以就只好 乖乖滚去用了两个数组 第一个 dx[] 第二个 dy[] 用于模拟一会的访问。
3.然后还需要一个char [] 的数组 用来存那些个点啊或者是 那个神奇的W 水洼!
4.还有要准备什么呢 为了一会方便,我把 输入的 多少行和多少列放在 全局变量下 其实 这个是个人的习惯 为什么呢 ,因为我想把判断这个点使用一个函数进行判断 而不是在主函数 或是解答函数里应用 所以全局的变量可以帮助我减少数字的传输。
5.数组开多大的问题 数组开多大 学长说了 数组开的大小应该是 题目要求的长度加上10 而成的,因为这样可以避免一些问题,况且我还认为在全局变量下定义的数组空间比较充足。这也是局部变量不能比的。
6.解决以上的问题之后我们 就可以写出前 5 条需要的东西 了 我们不需要想接下来要怎么去做 我们必须要相信自己的大脑 先把他认为对的东西给写出来吧。
int kx, ky;
bool vis[100 + 10][100 + 10];
char tu[100 + 10][100 + 10];
int dx[] = { -1,1,0,0,-1,-1,1,1 }; // 左右上下 左上 左下 右上 右下
int dy[] = { 0,0,1,-1,-1,1,1,-1 };
7.接下来就应该去写 解答函数了 ,我看一些ACM上的书籍 都不喜欢把程序写在主函数里 都是建立一个叫 solve的单独自定义函数,然后把代码放到 这个函数里面 因此就先定义 一个函数solve()返回值是void 所以 是 void solve(){}
8.接下来是读入数据 读入数据 要怎么读 是一个一个读 还是一行一行读 。如果是一个一个读的话 则需要的是两层循环,但是如果我用一个for循环可以读完 剩下的我们再进行规范遍历的话 就不用担心 输入超过的问题 。所以我考虑再三使用 %s对每行进行输入。
即 这样:
scanf("%d%d", &kx, &ky);
getchar();
for (int i = 0; i < kx; i++)
scanf("%s", tu[i]);
9.然后开始进行遍历的操作了 我们得先找到一个水洼·····等下 我忘记题目了 回去看一下 题目叫做的是统计 这个有多少水洼,那就说明还需要一个 cnt进行计数 所以定义了一个 int cnt=0;
10.然后遍历正式开始 我要做的是找到 W 这个字符 然后对这个 W 进行 深度搜索 那没得说 这个一定是双for完成搜索工作,所以就用了两个for
就是这样
int cnt = 0;
for(int i=0;i<kx;i++)
for(int j=0;j<ky;j++)
=====未知区域===
11.找 W 不是 直接写 if(tu[i][j]=='W') 吗?那么为什么还要写未知区域呢??因为 我还有所顾虑 这个点是不是之前已经被访问过了呢?是啊 我还记得我搞了一个标记的数组 里边装的全都是 0(false)啊!如果为0 是不是这个点就没被访问到?嗯一定是这样的,所以 if()的语句被筛选出来:
for(int i=0;i<kx;i++)
for(int j=0;j<ky;j++)
if (tu[i][j] == 'W'&&vis[i][j] == 0) {
//未知区域
}
12.接下来要干什么?没错就是找出这个 牵一发而动全身 的 发所有八联通的水洼W是不是 这下就是正牌的dfs 开始了
所以 不要多想 就是 dfs()
AC代码:
#include <cstdio>
#include <iostream>
using namespace std;
int kx, ky;
bool vis[100 + 10][100 + 10];
char tu[100 + 10][100 + 10];
int dx[] = { -1,1,0,0,-1,-1,1,1 }; // 左右上下 左上 左下 右上 右下
int dy[] = { 0,0,1,-1,-1,1,1,-1 };
bool pdst(int tx,int ty) {
if (tx < 0 || ty >= ky || vis[tx][ty] || tx >= kx || ty < 0 || tu[tx][ty] == '.')
return false;
return true;
}
void dfs(int x,int y) {
vis[x][y] = true;
for (int i = 0; i < 8; i++) {
int tx = x + dx[i];
int ty = y + dy[i];
if (pdst(tx, ty)) {
dfs(tx, ty);
}
}
}
void solve() {
scanf("%d%d", &kx, &ky);
getchar();
for (int i = 0; i < kx; i++)
scanf("%s", tu[i]);
int cnt = 0;
for(int i=0;i<kx;i++)
for(int j=0;j<ky;j++)
if (tu[i][j] == 'W'&&vis[i][j] == 0) {
cnt++;
dfs(i, j);
}
printf("%d",cnt);
}
int main() {
solve();
return 0;
}
~ dfs