[编程题]水平线

题目:
伞屉国是一个以太阳能为主要发电手段的国家,因此他们国家中有着非常多的太阳能基站,链接着的基站会组合成一个发电集群。但是不幸的是伞屉国不时会遭遇滔天的洪水,当洪水淹没基站时,基站只能停止发电,同时被迫断开与相邻基站的链接。你作为伞屉国的洪水观察员,有着这样的任务:在洪水到来时,计算出发电集群被洪水淹没后被拆分成了多少个集群。

由于远古的宇宙战争的原因,伞屉文明是一个二维世界里的文明,所以你可以这样理解发电基站的位置与他们的链接关系:给你一个一维数组a,长度为n,表示了n个基站的位置高度信息。数组的第i个元素a[i]表示第i个基站的海拔高度是a[i],而下标相邻的基站才相邻并且建立链接,即x号基站与x-1号基站、x+1号基站相邻。特别的,1号基站仅与2号相邻,而n号基站仅与n-1号基站相邻。当一场海拔高度为y的洪水到来时,海拔高度小于等于y的基站都会被认为需要停止发电,同时断开与相邻基站的链接。

输入描述:

每个输入数据包含一个测试点。

第一行为一个正整数n,表示发电基站的个数 (0 < n <= 200000)

接下来一行有n个空格隔开的数字,表示n个基站的海拔高度,
第i个数字a[i]即为第i个基站的海拔高度,对于任意的i(1<=i<=n),(0 <= a[i] < 2^31-1)

接下来一行有一个正整数q(0 < q <= 200000),表示接下来有q场洪水

接下来一行有q个整数,第j个整数y[j]表示第j场洪水的海拔为y[j],对于任意的j(1<=j<=n),(-2^31 < y[j] < 2^31-1)

输出描述:

输出q行,每行一个整数,第j行的整数ans表示在第j场洪水中,发电基站会被分割成ans个集群。
标准答案保证最后一个整数后也有换行。

示例:

输入
10
6 12 20 14 15 15 7 19 18 13 
6
15 23 19 1 17 24
输出
2
0
1
1
2
0

解析:
这道题有两个要点;
一:如何判断集群的数量。
一个集群,其两端必然是沉默的。因此,每次洪水后,我们当然可以对所有基站遍历一遍,按照凸点数计数,但这种方法就导致时间复杂度过高:数组长度*洪水次数

二:如何缩小时间复杂度
我们分析前一个方法导致的过长复杂度,显然是由于每次洪水我们都需要重新判断所有的基站情况,而我们每次都需要判断又是由于因为我们对集群计数的方法是靠顺序遍历的原因,因此所有的问题归根于计数方法。

那还有什么方法可以判断计数?
分析计数变化,是由于基站的沉没与升起导致陆地与海的相连情况变化导致的。

1、当沉没前基站两旁是没有其他基站浮起的,此时海洋的部分被陆地的部分相隔,因此当其沉没时,两处海洋部分连在一起,总集群数-1;
在这里插入图片描述
2、当沉没前基站有一旁是没有基站浮起的,而另一旁的基站是浮起的,此时的基站是集群的两端,当其沉没时,这端头后面的基站继续隔绝着海洋与陆地,海洋与陆地的相连状况没有发生变化,因此集群数不变。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210323031150689.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ub
mV0L3FxXzQzNTMwNzcz,size_16,color_FFFFFF,t_70)
3、当沉没前基站两旁的基站都是浮起的,那么当它下沉时,是制造出一片新的海,把陆地隔绝了,此时集群数+1
在这里插入图片描述
因此,倘若洪水是逐渐上涨的,则有基站只存在沉没的情况,这样,我们对集群数的计数只需查看沉没的基站的周边变化即可。而使洪水逐渐上涨与对基站状况的判断则可以通过对洪水高度以及基站高度两者的排序完成。

代码:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

//分别存储基站与洪水的序号以及高度
class Num
{
public:
	int idx;
	int height;
	Num(int idx,int height):idx(idx),height(height){}
};

//定义sort()函数第三参数,使其它按照类的高度由小往大排序
bool cmp(Num a,Num b)
{
	return a.height < b.height;
}

//存储基站与洪水信息
vector<Num> station, flood;
//存储洪水信息
vector<int> v;
//存储每次洪水结果
int arr[200005] = {};
//存储每座基站的状况,以0表示未沉没,以1表示已沉没
int status[200005] = {};

//基站数量以及洪水数量
int n, m;

int main()
{
	//填充基站信息
	cin >> n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin >> x;
		Num temp(i, x);
		station.push_back(temp);
	}

	//第0座基站以及第n+1座基站当然是已经沉没的了
	status[0] = status[n + 1] = 1;

	//填充洪水信息
	cin >> m;
	for(int i=1;i<=m;i++)
	{
		int x;
		cin >> x;
		Num temp(i, x);
		flood.push_back(temp);
	}

	//对两者排序
	sort(station.begin(), station.end(),cmp);
	sort(flood.begin(), flood.end(),cmp);

	//初始集群数量为1
	int ans = 1;

	//记录上次淹没的位置
	int last = 0;

	//洪水开始上涨
	for(int i=0;i<m;i++)
	{
		//查看洪水是否把所有基站淹没以及对洪水与基站高度比较
		while (last<n&&station[last].height<=flood[i].height)
		{
			//获取被淹没基站的序号
			int idx = station[last].idx;

			//记录它的沉没
			status[idx] = 1;

			//查看淹没基站两旁基站的状况
			//如果两旁的都已经沉没,则集群数-1
			if(status[idx-1]==1&&status[idx+1]==1)
			{
				ans--;
			}
			//如果其中一旁沉没而另一旁没有沉没,则集群数不变
			else if((status[idx - 1] == 1 && status[idx + 1] == 0)|| (status[idx - 1] == 0 && status[idx + 1] == 1))
			{
				ans += 0;
			}
			//如果两旁的都没有沉没,则集群数+1
			else if (status[idx - 1] == 0 && status[idx + 1] == 0)
			{
				ans++;
			}

			//对比下一座基站
			last++;
		}

		//记录此次洪水结果
		arr[flood[i].idx] = ans;
	}

	//输出每次洪水结果
	for(int i=1;i<=m;i++)
	{
		cout << arr[i] << endl;
	}
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值