洛谷P2919 [USACO08NOV]Guarding the Farm S
这道题中小山丘的定义简单来说就是:从一个小山丘的最高点开始,高度始终向四周递减或不变,例如样例中的小山丘是:
a a a a a 0 b
a a a a a 0 b
a a a a a 0 0
a a a a a 0 0
a a 0 0 0 c 0
0 0 0 c c c 0
0 c c c c c 0
0 c c c c c 0
于是我们有了这样的思路:使用一个结构体存储一个点的高度、坐标,输入之后排序,然后从最高的点开始搜索。
由于除了最高点,其他点都有可能是山丘中的非最高点或者山丘中的最高点,所以还需要对访问过的点进行标记,这样就可以从一个山丘的最高点开始搜索了。
具体代码(本人菜,勿喷):
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 750;
struct node
{
int h;
int x;
int y;
};
bool cmp(node a, node b)//指定排序规则
{
return a.h > b.h;
}
node h_[MAXN * MAXN];
bool visited[MAXN][MAXN];
int n, m, h[MAXN][MAXN], moveX[10] = {-1, -1, -1, 0, 0, 1, 1, 1};
int moveY[10] = {1, 0, -1, 1, -1, 1, 0, -1}, ans;
void dfs(int x, int y)//当前坐标 x为行,y为列
{
visited[x][y] = true;
for (int i = 0; i < 8; i++)
{
int u = x + moveX[i], v = y + moveY[i];
if (u < 0 || u >= n || v < 0 || v >= m)
{
continue;
}
if (visited[u][v] == true)
{
continue;
}
if (h[u][v] > h[x][y])//如果遇到比当前高的点则换方向
{
continue;
}
dfs(u, v);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf("%d", &h[i][j]);
h_[i * m + j].h = h[i][j];//i(读取的行数)*m(每行m个)+j(当前行的第j个)就是当前下标
h_[i * m + j].x = i;
h_[i * m + j].y = j;
}
}
sort(h_, h_ + m * n, cmp);//排序
for (int i = 0; i < m * n; i++)
{
int u = h_[i].x, v = h_[i].y;
if (visited[u][v] == false)//如果当前点没有访问过,则说明遇到新的山丘,ans++
{
ans++;
dfs(u, v);
}
}
printf("%d", ans);
}
(如果加上O2优化还能快一点,不过不加也能过)
如有错误或者可以改进的地方,请在评论区提出!谢谢!!