话说上题中,ycb刚在博知楼饮水机排完队打水,女朋友来电话说也想喝水,让ycb去接水,ycb为了方便就要把自己的水端去给女朋友,可谁知刚走到女朋友跟前,不小心将水全部洒在了地上(如果瓷砖上有水,则水都正好覆盖整块瓷砖,不考虑瓷砖之间的缝隙),ycb的女朋友很生气,对ycb说:”你要是数不清现在教室里有多少个水湾咱俩就分手好了!”。ycb数学不太好,他比较头疼这件事,现在需要你的帮助.
输入第一行包括两个整数n,m.表示教室的长,宽. (1<=n,m<=1000);
第二行到n+1行每行m个字符表示有m块瓷砖,’*’表示瓷砖上有水,‘.’表示没水.
只有一个整数,输出水湾的个数.(若两块瓷砖都有水并且瓷砖之间有一条公共边,则算一个水湾)。
2 2
.*
*.
2
3 3
.*.
***
.*.
1 这个题目可以用深搜,也可以用广搜,先用深搜: 先显示我代码:这个深搜用到着色法的原理,即在二维数组中检验相连的瓷砖时。#include<stdio.h> #include<string.h> #include<math.h> #include<queue> using namespace std; char ch[1001][1001]; int book[1001][1001]; int flash[1001][1001]; int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0} }; int ans; int n,m; void dfs(int x,int y) { int tx,ty; for(int i=0;i<4;i++) { tx=x+dir[i][0]; ty=y+dir[i][1]; if(tx<0||tx>n-1||ty<0||ty>m-1) continue; if(book[tx][ty]==0&&ch[tx][ty]=='*') { book[tx][ty]=1; flash[tx][ty]=1; dfs(tx,ty); } } } int main() { scanf("%d%d",&n,&m); getchar(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { scanf("%c",&ch[i][j]); } getchar(); } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(ch[i][j]=='*'&&flash[i][j]==0) { ans++; book[i][j]=1; flash[i][j]=1; dfs(i,j); } } } printf("%d\n",ans); }
下面是我刚开始在dfs中使用的普通代码,这个地方导致我TLEvoid dfs(int x,int y) { int tx,ty; if(ch[x][y]=='.') return; for(int i=0;i<4;i++) { tx=x+dir[i][0]; ty=y+dir[i][1]; if(tx<0||tx>n-1||ty<0||ty>m-1) continue; if(book[tx][ty]==0&&ch[tx][ty]=='*') { book[tx][ty]=1; flash[tx][ty]=1; dfs(tx,ty); book[tx][ty]=0; } } } 这种写法使得在dfs中多了没有用的return,使得时间超时,但是在第一种代码中,当检验完全部之后就会自己结束函数 。 注意加记住:以后再遇到连体问题并且想使用dfs时,一定要记住在里面不要加多余的return条件和book回溯条件,因为 这些条件他自己会完成。 现在奉献上雨神的代码(也是深搜,找出了我的错误)
*#include <stdio.h> #include <string.h> int e[1001][1001]; int n,m,sum; void dfs(int x,int y); int main() { int i,j; char a[1001]; char ch; while(scanf("%d%d",&n,&m)!=EOF) { ch=getchar(); for(i=1;i<=n;i++) { scanf("%s",a); for(j=1;j<=m;j++) { if(a[j-1]=='.') { e[i][j]=0;//meishui } else { e[i][j]=1; } } ch=getchar(); } sum=0; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { if(e[i][j]==1) { sum++; dfs(i,j); } } } printf("%d\n",sum); } return 0; } void dfs(int x,int y) { int next[4][2]={0,-1,-1,0,0,1,1,0}; int i,j,tx,ty; for(i=0;i<4;i++) { tx=x+next[i][0]; ty=y+next[i][1]; if(tx<1||tx>n||ty<1||ty>m) continue; if(e[tx][ty]==1) { e[tx][ty]=-sum; dfs(tx,ty); } } return; }
是不是比我的简单,是的,他的想法是,先把字符串二维数组转换成int型数组,然后在dfs的时候,当检验过该点的
时候,马上改变该点的值,那么下一次的时候就知道该点走过了,我的想法是另外开辟一个二维数组,实现和book一样
的作用,这样就知道该点在原来检验过了,反正自己习惯吧,不过我也要练练。
另外,考试的时候我还想到了广度优先搜索,
但是广搜还有一个地方 没弄好,就是两个的交点处,不知道怎么弄.
就是相当于找小岛的个数,每次是1.#include<stdio.h> #include<string.h> #include<math.h> #include<queue> using namespace std; int ans; char ch[1001][1001]; int book[1001][1001]; int dir[4][2]={0,1,1,0,-1,0,0,-1}; struct stu { int x; int y; }now,ne; int bfs(int x,int y) { queue<stu>Q; now.x=x; now.y=y; Q.push(now); while(!Q.empty()) { now=Q.front(); Q.pop(); for(int i=0;i<4;i++) { ne.x=now.x+dir[i][0]; ne.y=now.y+dir[i][1]; if(book[ne.x][ne.y]==0&&ch[ne.x][ne.y]=='*') { book[ne.x][ne.y]=1; Q.push(ne); } } } return 1; } int main() { int n,m; scanf("%d%d",&n,&m); getchar(); for(int i=0;i<n;i++) { scanf("%s",ch[i]); } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(ch[i][j]=='*'&&book[i][j]==0) ans+=bfs(i,j); } } printf("%d\n",ans); }