2 条题解
-
0
写的时候,总感觉是管理员设错了。
这是一道非常非常普通的bfs。
接下来让我们来仔细的分析一下。
First
先看题干,题目中的意思是输入一张 n * n 的地图,让我们输出地图中的山峰和山谷。
题中的山峰和山谷内的任意一块一定是相平的。 那么,这题的目的也就清楚了。这是一道搜地图中的连通块的模板题。
不过要注意:
1.每个连通块不一定是山峰或山谷,也可能什么也不是。我们要及时判断。 2.每一次扩展需要探索的点时,要注意为8个方向,代码实现时要小心,不能思维定式。
对于 1. 我们的解决办法是在搜连通块时,如果要扩展的地方低于 或 高于当前的位置时,分别用变量记录,但并不放入搜索队列中。
对于 2. 我们的解决办法就轻松多了,只要在定义方向数组时横纵坐标都为8就行了
好了,
我们已经将题干中的信息都提取出来了,算法也清晰了,接下来就是代码的实现问题了。
在代码中的注意点也会标出
#include<bits/stdc++.h> using namespace std; int n; int a[10001][10001]; int dep[10001][10001];//这个数组主要表明地图中已经走过的位置 对代码的优化有很大帮助 但是要注意 在比赛中前往不要定义这么大,会爆的(~~我已经有深刻的体会了~~) struct xi{ int x , y; }c[1000001];//这里的队列使用一个struct来表示当前要搜的位置的横纵坐标 int h = 1 , t = 1; /*这里的队列是我手打的习惯了STL的小伙伴可能会不习惯, 但是我还是要说一声 head 为 t , tail 为 h ,千万不要看错*/ int ans1 = 0 , ans2 = 0;//表示山峰 和 山谷的数量 int ax[8] = {-1 , -1 , -1 , 0 , 1 , 1 , 1 , 0}; int ay[8] = {-1 , 0 , 1 , 1 , 1 , 0 , -1 , -1};//方向数组要小心定义 , 弄清楚各个方向 void bfs(int x , int y){ int xa = 0 , ya = 0;//表示当前的平地的周围是否有低地 或 高地 h ++;//当上一次while退出时 , h == t ,所以此时要++ c[t].x = x , c[t].y = y;//把起始位置附入队列的头 do{ // cout << c[t].x << " " << c[t].y << endl; // dep[c[t].x][c[t].y] = 1;检查代码 可以忽略 但是大家在比赛中的调试代码千万不要留下 for(int i = 0;i < 8;i ++){//搜8个方向 int xx = c[t].x + ax[i] , yy = c[t].y + ay[i]; if(xx <= 0 || xx > n || yy <= 0 || yy > n)continue;//越界跳过 if(a[xx][yy] < a[c[t].x][c[t].y]){//表示目标位置低于当前位置 即 当前的平地周围有低地 xa = 1; } else if(a[xx][yy] > a[c[t].x][c[t].y]){//表示目标位置高于当前位置 即 当前的平地周围有高地 ya = 1; } if(dep[xx][yy])continue;//这里要注意 判断是否搜过要在判断目标位置之后。 //不懂得小伙伴可以调换一下,测试一下 一定会出错 if(a[xx][yy] == a[c[t].x][c[t].y]){//表示目标位置等于当前位置 即 目标位置是当前的平地的一部分可以入队 c[h].x = xx; c[h].y = yy; dep[c[h].x][c[h].y] = 1; h ++;//入队操作 } } // cout << " 1 " << endl; t ++; }while(h > t); if(xa == 1){ if(ya == 0)//表示当前的平地周围都较低 当前的平地为为山峰 { ans1 ++; } } else if(ya == 1){ //表示当前的平地周围都较高 当前的平地为山谷 ans2 ++; }//这就是解决注意 1. 的方法 return ; } void print(){ /*这里要说一声 当整个地图都为同一高度时 它既是一个山峰 也是一个山谷 所以在输出是要把整张地图都遍历一遍*/ if(ans1 || ans2){ cout << ans1 << " " << ans2 << endl; return ; } int x = 0; for(int i = 2;i <= n;i ++) for(int j = 2;i <= n;i ++){ if(a[i][j] != a[i - 1][j]) x = 1; } for(int i = 2;i <= n;i ++) if(a[i][1] != a[i - 1][1]) x = 1; if(x){ cout << ans1 << " " << ans2 << endl; return ; } cout << 1 << " " << 1 << endl; return ; } int main(){ // freopen("hill.in" , "r" , stdin); // freopen("hill.out" , "w" , sdtout); //考试的时候 freopen一定不要忘记取消注释 cin >> n; for(int i = 1;i <= n;i ++) for(int j = 1;j <= n;j ++) cin >> a[i][j]; /* for(int i = 1;i <= n;i ++){ for(int j = 1;j <= n;j ++) cout << a[i][j] << " "; cout << endl; } *///个人习惯 for(int i = 1;i <= n;i ++) for(int j = 1;j <= n;j ++) if(!dep[i][j]){ // cout << i << " " << j << endl; dep[i][j] = 1; bfs(i , j); } print(); return 0; }以上为完整的代码。 (
如果你还没看懂,就再看一遍吧!)
END
(
写的不好,大佬勿喷) -
0
#include<bits/stdc++.h> using namespace std; const int N=1010; int n,h[N][N],w;//w==1谷 , w==2峰 bool vis[N][N]; int dx[8]={-1,-1,-1,0,0,1,1,1}; int dy[8]={-1,0,1,-1,1,-1,0,1}; void dfs(int x,int y) { vis[x][y]=1; //标记当前点已访问 for(int i=0;i<8;i++)//搜索与当前点相邻的8个点 { int xx=x+dx[i],yy=y+dy[i]; if(!(xx>=1&&xx<=n&&yy>=1&&yy<=n))continue; if(h[xx][yy]==h[x][y]&&vis[xx][yy]==0) dfs(xx,yy); else if( (h[xx][yy]<h[x][y]&&w==1) || (h[xx][yy]>h[x][y]&&w==2) ) //周围既有比它高的又有比它低的 则它什么也不是,为-1 w=-1; else if(w==0)//没确定是是峰还是谷,为0。搜到与当前搜索高度不同的点 暂且标记当前搜索区域是峰还是谷 { if(h[xx][yy]<h[x][y])w=2; if(h[xx][yy]>h[x][y])w=1; } } } int main() { scanf("%d",&n); bool bk=1;int v=-1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&h[i][j]); if(v==-1)v=h[i][j]; if(h[i][j]!=v)bk=0; //如果有高度不相同的点 } if(bk){printf("1 1\n");return 0;} memset(vis,0,sizeof(vis)); int a=0,b=0; //a表示山峰个数,b表示山谷个数 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(vis[i][j]==0)//找到一个没搜过的点开始搜索 { w=0; //w=0表示当前点还没确定是山峰还是山谷 dfs(i,j); if(w==1)a++; else if(w==2)b++; } printf("%d %d\n",b,a); return 0; }
- 1
信息
- ID
- 2755
- 时间
- 2000ms
- 内存
- 64MiB
- 难度
- 6
- 标签
- 递交数
- 22
- 已通过
- 11
- 上传者