题意:
输入一个 m 行 n 列的字符矩阵,统计字符 @ 能组成多少八连块,如果两个字符 @ 所在的格子相邻(横竖或者对角线的方向),就
说他们组成了一个八连块,问图中一共有多少个八连块。
Sample Input:
1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0
Sample Output:
0
1
2
2
分析:
图和二叉树一样,也有自己的dfs 和 bfs遍历,一般dfs用来求连通块问题,bfs用来找最短路问题,这个题目就是一个典型的dfs求八
连块的问题,可以从每个 @ 字符出发,递归遍历他周围八个方向的字符,看是否是 @ 格子,如果是就标记一下,证明该格子遍历
过,这样在以后的访问的时候,就能知道他是否被访问过,从而避免同一个格子被访问多次。下面的代码用一个二重循环来寻找八
连块,当然也可以用常量数组或者8条dfs遍历,在这里说一下,图的dfs遍历用递归实现,bfs遍历则是用队列(或者数组)实现,
类似的还有求二连块,四连块,等等,都可以用dfs遍历来实现,只需要改一下行走函数就可以。
下面上代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m, maxz[105][105];
char str[105][105];
void dfs(int r,int c,int id)
{
if(r < 0 || r >= n ||c < 0 ||c >= m)
return;
if(maxz[r][c] > 0 || str[r][c] != '@')
return;
maxz[r][c] = id;
for(int dr = -1; dr <= 1; dr++)///两个方向同时移动可以往八个方向移动
for(int dc = -1; dc <= 1; dc++)///而四连块则是单移动,仅一个for循环。
if(dr != 0 || dc != 0)///这儿同时体现八连块,八方向
dfs(r + dr, c + dc, id);
}
int main()
{
while(scanf("%d%d",&n, &m) == 2&&n,m)
{
for(int i = 0; i < n; i++)
cin >>str[i];
memset(maxz, 0, sizeof(maxz));
int cnt = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
if(str[i][j] == '@'&&maxz[i][j] == 0)
{
dfs(i,j, ++cnt);
cnt = max(0, cnt);
}
}
cout <<cnt<<endl;
}
}
下面上四连块:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100+5;
int maze[maxn][maxn];///顶点访问状态
int R,C,K;///R行C列K个水块
int cnt,ans;///cnt是计算访问的格子数
///两个表示方向数组
int dr[]= {-1,1,0,0}; //上,下,左,右
int dc[]= {0,0,-1,1};
void dfs(int r,int c) ///r是行坐标,c是列坐标
{
if(r<1||r>R ||c<1||c>C || maze[r][c]==0)
return ;///超出范围或已经访问过的格子
maze[r][c] = 0;///访问的格子
cnt++;
for(int d=0; d<4; d++)///四连块
dfs(r+dr[d],c+dc[d]);
}
int main()
{
while(scanf("%d%d%d",&R,&C,&K) == 3)
{
for(int i=1; i<=R; i++)///一定是从1开始
for(int j=1; j<=C; j++)
maze[i][j] = 0;///将初始的maze数组全部设置成false
while(K--)///输入有水的格子坐标,设置成true
{
int i,j;
scanf("%d%d",&i,&j);
maze[i][j] = 1;
}
ans=0;
for(int i=1; i<=R; i++)
for(int j=1; j<=C; j++)
if(maze[i][j]==1)
{
cnt=0;
dfs(i,j);
ans=max(ans,cnt);///如果没有则输出0
}
printf("%d\n",ans);
}
return 0;
}
代码实现:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int map[650][650],p[650][650],x[650],y[650],vis[650];
int n,num,t,k;
char s[650][650];
bool Search(int i)///其实就是一个dfs
{
int j;
for(j=0; j<num; j++)
{
if(map[i][j] && !vis[j])
{
vis[j]=1;
if(!y[j]||Search(y[j]))
{
y[j]=i;
x[i]=j;
return true;
}
}
}
return false;
}
int match()
{
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
int ans=0;
for(int i=0; i<num; i++)///寻找増广路
{
memset(vis,0,sizeof(vis));
if(Search(i))///统计满足二连块的个数
ans++;
}
return ans/2;
}
int main()
{
k=1;
cin>>t;
while(t--)
{
memset(map,0,sizeof(map));
cin>>n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cin>>s[i][j];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(s[i][j]=='#')
p[i][j]=num++;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(s[i][j]=='#')
{
if(j<n-1 && s[i][j+1]=='#')
{
map[p[i][j]][p[i][j+1]]=1;
map[p[i][j+1]][p[i][j]]=1;
}
if(j<n-1 && s[i+1][j]=='#')
{
map[p[i][j]][p[i+1][j]]=1;
map[p[i+1][j]][p[i][j]]=1;
}
}
}
}
int p=match();
printf("Case %d: %d\n",k++,p);
}
return 0;
}