深搜学习 ~

LINK:https://vjudge.net/problem/POJ-2386

学C 几个周以来,真的很想写出一个"技术"的东西,看了一下深搜不是太难,所以就试了一下。写的不好,总结~


Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water ('W') or dry land ('.'). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors. 

Given a diagram of Farmer John's field, determine how many ponds he has.
Input
* Line 1: Two space-separated integers: N and M 

* 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.
Output
* Line 1: The number of ponds in Farmer John's field.
Sample Input
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
3
Hint
OUTPUT DETAILS: 

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 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值