Summits poj3503

排序后bfs,O(h*w*log(h*w)),这题算法简单,但需要思考,估计比赛中出现这题多半要跪了,解决这道题基于这样的性质,如果A可以在满足条件(即其路径经过节点的高度都大于h[A]-d)的情况下到达B,C在满足条件下可以到达B,且h[A] > h[B],则C一定可以满足条件到达A(因为h[B]-d一定大于h[A]-d)。

所以我们可以按照节点高度逆序依次为起点进行bfs,每次在满足条件下发现尽可能多的节点,且将访问过的节点vis标记为h[cur](cur为此次bfs的起点),在每次bfs之前设置count = 0,如果在访问节点途中发现了高度相同的节点且之前没有被访问过就++count,如果发现了某节点的vis > ch,说明之前由高度更大的节点可以访问此节点,则基于上面的性质,我们可以断定此次访问的高度为h[cur]的节点都不是summit,如果没有发现,说明此次访问的高度为h[cur]的节点全部是summit,让答案加上count即可,由于每个节点只能被标记一次所以这个过程时间复杂度为O(h*w),所以总的复杂度就是排序的时间复杂度。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(510);
const int SIGMA_SIZE(82);
const int MAXM(110);
const int MAXE(200010);
const int MAXH(18);
const int INFI((INT_MAX-1) >> 2);
const int BASE(131);
const int MOD(20071027);
const ULL LIM(1000000000000000ull);

struct NODE
{
	int x, y, hei;
	friend bool operator <(const NODE &op1, const NODE &op2)
	{
		return op1.hei < op2.hei;
	}
};

int mp[MAXN][MAXN];
int vis[MAXN][MAXN];

int m_x[4] = {0, -1, 0, 1};
int m_y[4] = {-1, 0, 1, 0};

int ch, lim, count;
int h, w, d;
int qx[MAXN*MAXN], qy[MAXN*MAXN];
int front, back;
NODE arr[MAXN*MAXN];
int ind;

bool bfs(int cx, int cy)
{
	front = back = 0;
	qx[back] = cx;
	qy[back++] = cy;
	vis[cx][cy] = ch;
	++count;
	int tx, ty;
	bool ret(true);
	while(front < back)
	{
		cx = qx[front], cy = qy[front++];
		for(int i = 0; i < 4; ++i)
		{
			tx = cx+m_x[i];
			ty = cy+m_y[i];
			if(tx >= 1 && tx <= h && ty >= 1 && ty <= w)
			{
				if(mp[tx][ty] <= lim)
					continue;
				if(vis[tx][ty] > ch)
				{
					ret = false;
					continue;
				}
				if(vis[tx][ty] == ch)
					continue;
				if(mp[tx][ty] == ch)
					++count;
				vis[tx][ty] = ch;
				qx[back] = tx;
				qy[back++] = ty;
			}
		}
	}
	return ret;
}

void solve()
{
	int ans = 0;
	sort(arr, arr+ind);
	memset(vis, -1, sizeof(vis[0])*(h+1));
	for(int i = ind-1; i >= 0; --i)
		if(vis[arr[i].x][arr[i].y] == -1)
		{
			ch = arr[i].hei;
			lim = ch-d;
			count = 0;
			if(bfs(arr[i].x, arr[i].y))
				ans += count;
		}
	printf("%d\n", ans);
}

int main()
{
    int TC;
    scanf("%d", &TC);
    while(TC--)
    {
		ind = 0;
        scanf("%d%d%d", &h, &w, &d);
        for(int i = 1; i <= h; ++i)
            for(int j = 1; j <= w; ++j)
			{
                scanf("%d", mp[i]+j);
				arr[ind].x = i;
				arr[ind].y = j;
				arr[ind++].hei = mp[i][j];
			}
		solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值