JZOJ. 3450 山峰 summits

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值