51nod 1276 岛屿的数量 思维题,很棒的题目

本文介绍了解决51nod1276题目的有效算法。通过离线处理和排序技巧,实现了对岛屿数量变化的有效追踪,解决了洪水淹没岛屿过程中岛屿数量的变化计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门51nod 1276



题目大意:由于是中文题就不再描述了。



Input示例
5 4
2
1
3
2
3
0
1
3
2
Output示例
1
2
0
2



思路

第一思路肯定是暴力的方法,每次询问都去查询被淹没的岛屿和不相连的岛屿数,这样的时间复杂度是O(n)*O(q),会超时。网上的思路一般都是离线处理,也就是说针对每个询问不立刻给出答案,而是等询问全部给出后一起给出答案。由于水会先淹没高度低的岛屿,所以如果先处理高度低的岛屿再处理高度高的就避免了重复计算,大大的降低了时间复杂度。


经过观察我们发现,只有淹没的岛屿为山峰(比两边都高)的时候,原来的岛屿数要-1,如果淹没的是山谷(比两边都低),一个岛变成两个,则原来的岛屿数+1. 这里要注意首尾两个岛屿比较特殊,如果它们是孤立的岛屿的话,淹没它们则岛屿数+1,否则不变化。


这样一来,我们找到了方法也找到了规律。不过还有几个难点:


1.既然要对岛屿和询问从低到高处理,那么就要对其排序,怎么确定在原数组中的位置呢?很简单,用结构体记录位置就可以了。

2.怎么判断为山峰还是山谷,我们注意到可能存在这样的数据:1 6 6 6 1,如果单纯的判断是否比两边高或比两边低是不行的。这里就有一个很巧妙的方法:当该岛屿要被淹没时,如果两边的岛屿都没被淹没,则为山谷;如果两边的岛屿都被淹没,则为山峰。


#include<stdio.h>
#include<string.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

struct node
{
	int val,pos; //记录值和位置 
} a[50010],q[50010];

int cmp(node x,node y)
{
	return x.val<y.val;
}

int main()
{ //f为0表示未被淹没,为1表示已被淹没 
	int i,j,n,m,sum,f[50010],ans[50010];
	while(~scanf("%d%d",&n,&m))
	{
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i].val);
			a[i].pos=i;			
		}
		sort(a,a+n,cmp);
		for(i=0;i<m;i++)
		{
			scanf("%d",&q[i].val);
			q[i].pos=i;
		}
		sort(q,q+m,cmp);	
		j=0;
		sum=1; //sum记录岛屿数,初始时只有一个岛屿 
		memset(f,0,sizeof(f));
		for(i=0;i<m;i++)
		{ //针对从小到大的每个询问 
			while(a[j].val<=q[i].val&&j<n)
			{ //扫描当前水平面可以淹没的岛屿 
				if(a[j].pos==0)
				{ //如果是第一个岛 
					if(f[a[j].pos+1]==1) sum--;
				}
				else if(a[j].pos==n-1)
				{ //如果是最后一个岛 
					if(f[a[j].pos-1]==1) sum--;
				}
				else 
				{
					if(f[a[j].pos+1]&&f[a[j].pos-1]) sum--; //如果两边都被淹没,则为山峰 
					else if(!f[a[j].pos+1]&&!f[a[j].pos-1]) sum++; //如果两边都未被淹没,则为山谷 
				}
				f[a[j].pos]=1; //当前岛屿淹没 
				j++;
			}
			ans[q[i].pos]=sum; //记录答案 
		}
		for(i=0;i<m;i++) printf("%d\n",ans[i]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值