学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO备考冲刺必刷题 | 汇总-CSDN博客
【题目描述】
由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用一个 N×M(1≤N≤100,1≤M≤100) 的网格图表示。每个网格中有水(W) 或是旱地(.)。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。
【输入】
输入第 1 行:两个空格隔开的整数:N 和 M。
第 2 行到第 N+1 行:每行 M 个字符,每个字符是 W 或 .,它们表示网格图中的一排。字符之间没有空格。
【输出】
输出一行,表示水坑的数量。
【输入样例】
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
【输出样例】
3
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, m, ans=0, vis[105][105]={0};
int dx[8]={-1,-1,-1,0,0,1,1,1}, dy[8]={-1,0,1,-1,1,-1,0,1}; // 定义8个方向的偏移坐标
char a[105][105];
struct node {
int x, y;
};
int main()
{
cin >> n >> m; // 输入n和m
for (int i=1; i<=n; i++) { // 双重for循环遍历矩阵
for (int j=1; j<=m; j++) {
cin >> a[i][j]; // 输入每个位置的字符,W或.
}
}
for (int i=1; i<=n; i++) { // 双重for循环遍历矩阵
for (int j=1; j<=m; j++) {
if (a[i][j]=='W' && vis[i][j]==0) { // 当遇到水坑'W',且没有访问过时
ans++; // 水坑数量自增1
queue<node> q; // 定义队列
node tp = {i, j}; // 定义tp节点,此处用结构体来记录x和y坐标
q.push(tp); // 压入队列中
vis[i][j]=1; // 并标记该位置已来过
while (!q.empty()) { // 当队列不为空
node tp = q.front(); // 取出队头
q.pop();
for (int k=0; k<8; k++) { // 遍历8个方向
int xx = tp.x + dx[k]; // 得到移动后的x坐标
int yy = tp.y + dy[k]; // 得到移动后的y坐标
if (xx<1 || yy<1) continue; // 进行边界判断,超边界的继续循环
if (a[xx][yy]=='W' && vis[xx][yy]==0) { // 如果移动后仍为水坑'W',且没有访问过
node t = {xx,yy}; // 定义t
q.push(t); // 将t压入队列中
vis[xx][yy]=1; // 并标记该位置已来过
}
}
}
}
}
}
cout << ans << endl; // 最后输出水坑数量
return 0;
}
【运行结果】
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
3