(离散化)洛谷P1496火烧赤壁

洛谷P1496火烧赤壁

前言:首先这道题,可以用模拟过,模拟方法需要一些技巧,但是本文讲的是离散化方法,就忽略模拟法了。

算法分析1:首先,如果忽略本题的船的位置范围(本题船位置范围达到了10^9而且还包含负数),假设范围比较小且不包含正数,那么这道题的解法就是相当直观的,只需要用一个标记数组(bool数组),数组初始化时元素全部为false,然后主函数中将输入所涉及的范围全部打成true,最后再统计true的个数,就可以起到去重的作用。代码如下(该代码对于大多数输入样例,会出现数组越界的情况,因而该代码只作理解算法用,不可轻易运行!!!)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<vector>
#define ll long long
using namespace std;
const int maxn=10000000;
bool vis[maxn];
int n;
int ans=0;
int main(){
   

  cin>>n;
  int xx,yy;
  for(int i=0;i<n;i++){
   
  	cin>>xx>>yy;
  	for(int j=xx;j<yy;j++) vis[j]=true;//注意区间要左闭右开,否则会多算一个
	}
  
  for(int i=1;i<maxn;i++) if(vis[i]) ans++;
  
  cout<<ans;
  
  return 0;
}

算法分析2:上面的代码显然是无法解决这道题的,因为数组不可能开到10^9大也不可能出现负数下标(虽然负数下标编译器不会报错,甚至可能算出正确结果,但是数组越界是不要轻易尝试的)。但是我们还是希望能通过标记法来实现去重从而解决问题,那么该如何做才能解决数组范围不够用的问题?

通过仔细看题目的数据范围可以发现,虽然各个船只相距可能很远,但是船只的总数目却很少。我们可以尽情想象,就像长江虽然很长,但是长江上的船如果连起来,长度是远远小于长江的长度的。也就是说,假如我们真的有一个非常长的,并且有负数下标的数组,然后在此基础上,我们真的按照上面“算法分析1”的方法来做,那么当存储完数据之后,我们会发现数组中的元素是及其“稀疏”的,可能隔着很多false才会有几个true,这样我们就浪费了大量的空间。

再回到长江和船的场景,假如我们要量取长江上所有船的长度(和本题一样不算重复部分),那么我们完全不必也不可能真的派一个人,从长江头找到长江尾,一米一米地找。而是可以让每艘船给自己发送一条“信号”,信号包含了该船的首尾坐标,然后我们再只需要一个很小的bool数组(长度不会超过船只数量的两倍,因为一艘船两个坐标),就可以把这些信号存起来了,同时也可以统计出各艘船的相对位置关系。比如一艘船的真实坐标可能是(20000,45000),即从船头在20000处,船尾在45000处,但是由于20000在所有坐标中从小到大只排第二,而45000只排第4,那么我们的bool数组就可以只把2到4之间,置为true。此外,为了防止原坐标数据(20000,45000)遗失,我们可以设置一个离散化用的数组p,将p[2]置为20000,将p[4]置为45000,考虑到坐标的数据范围,数组p的元素设成long long 是完全存得下的。

具体算法如图所示,假设输入(和题上样例不一样)为
3
-1 1
2 9
7 11

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值