Problem
Description
作为地质学家的JIH,为了绘制地图进行了野外考察。考察结束,他得到了一张n*m的地面高度地图。为了科学研究,JIH定义了一种山峰叫做d-山峰。一个高度为h地点被称作d-山峰,只有满足从这里出发,在不经过小于等于h-d的地点的前提下无法达到比它更高的地方。JIH正纠结于怎么分礼物,标出d-山峰的任务就交给你了。
Input
第一行n,m,d
第二行开始,有一个n*m的矩阵表示地图,用空格隔开。
Output
输出d-山峰的个数。
Sample Input
6 10 2
0 0 0 0 0 0 0 0 0 0
0 1 2 1 1 1 1 0 1 0
0 2 1 2 1 3 1 0 0 0
0 1 2 1 3 3 1 1 0 0
0 2 1 2 1 1 1 0 2 0
0 0 0 0 0 0 0 0 0 0
Sample Output
4
Data Constraint
30% n,m<=10
100% n,m<=500
Hint
Solution
此题算法:Brute Force(暴力+剪枝)
30分方法(实际上我水到了60分):纯暴力!
请观看我的代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define N 502
using namespace std;
const int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int i,j,k,l,n,m,t,d,ans,a[N][N];
bool v[N][N],p;
void dg(int x,int y,int h)
{
int i;
if (a[x][y]>h) p=0;
if (p==0) return;
for (i=0;i<=3;i++)
{
int xx=x+fx[i][0],yy=y+fx[i][1];
if (xx>=1 && xx<=n && yy>=1 && yy<=m && a[xx][yy]>h-d && !v[xx][yy])
{
v[xx][yy]=1;
dg(xx,yy,h);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&d);
for (i=1;i<=n;i++)
for (j=1;j<=m;j++) scanf("%d",&a[i][j]);
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{
memset(v,0,sizeof(v));
v[i][j]=1;
p=1;
dg(i,j,a[i][j]);
if (p==1) ans++;
}
printf("%d",ans);
}
剩下的分怎么拿呢?
剪枝1:我们可以求出整个地图的最高点MAX,如果搜到的地点=MAX直接ans++。
剪枝2:我们不用每一次将标记数组清零,我们重新将每一个点的序号(你看着办)作为标记的数字,如果搜到这个数字则说明这个点已经走过了。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define N 502
using namespace std;
const int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int i,j,k,l,n,m,t,d,ans,a[N][N],v[N][N],MAX;
bool p;
void dg(int x,int y,int h,int note)
{
int i;
if (a[x][y]>h) p=0;
if (p==0) return;
for (i=0;i<=3;i++)
{
int xx=x+fx[i][0],yy=y+fx[i][1];
if (xx>=1 && xx<=n && yy>=1 && yy<=m && a[xx][yy]>h-d && v[xx][yy]!=note)
{
v[xx][yy]=note;
dg(xx,yy,h,note);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&d);
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
MAX=max(MAX,a[i][j]);
}
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (a[i][j]==MAX) ans++;
else
{
v[i][j]=(i-1)*n+j;
p=1;
dg(i,j,a[i][j],(i-1)*n+j);
if (p==1) ans++;
}
printf("%d",ans);
}
总结一下:当遇到多个暴力起点的时候,我们不用每一次将标记数组清空而使用上述方法,每一个起点用一个数字表示,这样可以省非常多的时间。
——2016.7.9